chorlton2080
Posts: 124
Joined: Sun Dec 23, 2012 9:44 pm

rc.local won't execute python mailer script (solved)

Fri Jul 05, 2013 7:51 pm

Hello

I have two RPi's. On the first I have a startup mailer written in Python which is called via rc.local. This works well.

I've copied the rc.local and the python script from the first RPi to the second. I've set the execution bit for the rc.local file.

If I do the following once I've logged in I get the result I'm after: an email with my internal and external IP address.

Code: Select all

sudo bash rc.local
However, the python script fails to execute at boot. I added the following into rc.local as a diagnostic:

Code: Select all

exec 2> /tmp.rc.local.debug
set -x
The output of that debug file is the following:

Code: Select all

+ sudo python /home/pi/scripts/startup_mailer.py
Traceback (most recent call last):
  File "/home/pi/scripts/startup_mailer.py", line 12, in <module>
    smtpserver = smtplib.SMTP('smtp.gmail.com', 587)
  File "/usr/lib/python2.7/smtplib.py", line 249, in __init__
    (code, msg) = self.connect(host, port)
  File "/usr/lib/python2.7/smtplib.py", line 309, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "/usr/lib/python2.7/smtplib.py", line 284, in _get_socket
    return socket.create_connection((port, host), timeout)
  File "/usr/lib/python2.7/socket.py", line 553, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
socket.gaierror: [Errno -2] Name or service not known
For reference here is the Python code:

Code: Select all

import urllib2
import subprocess
import smtplib
import socket
import string
from email.mime.text import MIMEText
import datetime
# Change to your own account information
to = 'XXXXXX' # enter your receiving email account here
gmail_user = 'XXXXXXXXX' # enter your gmail acc here to send 
gmail_password = 'XXXXXXXX' # enter your gmail password here 
smtpserver = smtplib.SMTP('smtp.gmail.com', 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo
smtpserver.login(gmail_user, gmail_password)
today = datetime.date.today()
ext_ip = urllib2.urlopen('http://checkip.dyndns.org').read()

# Very Linux Specific

arg='ip route list'
p=subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE)
data = p.communicate()
split_data = data[0].split()
ipaddr = split_data[split_data.index('src')+1]
my_ip = 'PiA IP: LAN  Address: %s' % ipaddr + (' External '+ ext_ip[56:91])
msg = MIMEText(my_ip)
msg['Subject'] = 'IP For RaspberryPi on %s' % today.strftime('%b %d %Y')
msg['From'] = gmail_user
msg['To'] = to
smtpserver.sendmail(gmail_user, [to], msg.as_string())
smtpserver.quit()
Can anyone offer help? As stated, this same script works fine on my other RPi and works when I invoke rc.local using "sudo bash rc.local"

Thank you
Last edited by chorlton2080 on Fri Jul 05, 2013 8:31 pm, edited 1 time in total.

chorlton2080
Posts: 124
Joined: Sun Dec 23, 2012 9:44 pm

Re: rc.local won't execute python script on identical RPi

Fri Jul 05, 2013 8:09 pm

Looks like it's solved.

For some reason my second RPi is slightly quicker to boot and therefore attempts to execute the script before the WiFi adapter has obtained an IP address, thus no internet socket yet exists.This is probably because this is a fresh install and I haven't added any services like Apache or Motion which load on boot (and therefore extend the time before which rc.local is run).

I solved it by placing the following before the call to python

Code: Select all

sleep 30

pjc123
Posts: 911
Joined: Thu Mar 29, 2012 3:37 pm

Re: rc.local won't execute python script on identical RPi

Sun Jul 07, 2013 10:40 am

chorlton2080 wrote:For some reason my second RPi is slightly quicker to boot and therefore attempts to execute the script before the WiFi adapter has obtained an IP address, thus no internet socket yet exists.
.

I had the same problem going from a Model B Rev 1 board (with Wheezy) to a Model B Rev 2 board (with Raspbian), the Rev 2 board with Raspbian being quicker to boot, and the wifi's network interface only intermittently getting an ip address. I solved the problem by adding a script that runs after boot that occasionally checks for an ip, and if not available, resets the network interface; this also solved the problem where I moved my pi too far from the router and the wifi connection was not reconnecting by itself once back in range.
My Raspberry Pi Project Page:
http://www.flaminghellmet.com/launch/

dalgibbard
Posts: 9
Joined: Fri Jun 07, 2013 4:39 pm

Re: rc.local won't execute python mailer script (solved)

Mon Oct 14, 2013 10:14 am

Really sorry for digging up an old thread... but the use of rc.local bugs me somewhat (and stumbled across this whilst doing something else :D)
The correct way to do this (as stated here: http://www.debian.org/doc/manuals/debia ... ng.en.html) is to create a valid init script in /etc/init.d/ and configure it to have a dependency on the networking.

See: https://wiki.debian.org/LSBInitScripts
Namely the sections that define "Required-Start:" as a parameter, and "$network" as a valid variable.

This will save you (potentially) having to watch the interfaces etc.

aunitt
Posts: 11
Joined: Tue Sep 18, 2012 8:43 pm

Re: rc.local won't execute python mailer script (solved)

Tue Dec 17, 2013 10:31 pm

Could you post your init scripts as I'd like to do this the proper way but it's a bit beyond my knowledge?

dalgibbard
Posts: 9
Joined: Fri Jun 07, 2013 4:39 pm

Re: rc.local won't execute python mailer script (solved)

Tue Dec 17, 2013 11:32 pm

Sure I'll try and get around to posting an example tomorrow. Stay tuned :)

dalgibbard
Posts: 9
Joined: Fri Jun 07, 2013 4:39 pm

Re: rc.local won't execute python mailer script (solved)

Mon Dec 23, 2013 12:30 pm

Apologies for the delay; here's an example one which i've been using to run a Python script as a daemon on startup- Just be sure to put it into /etc/init.d:

Code: Select all

#!/bin/sh
 
### BEGIN INIT INFO
# Provides: moonlighter
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Marine Aquarium Moonlighting
# Description: Analyses light levels, and calculates lunar cycle, to initiate artificial moonlight control.
### END INIT INFO
 
#### Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/home/moonlighter
DAEMON="$DIR/moonlighter_sched.py
DAEMON_NAME=moonlighter
#### 

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=moonlighter

############## END CUSTOMISATION
 
# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid
 
. /lib/lsb/init-functions
 
do_start () {
log_daemon_msg "Starting system $DAEMON_NAME daemon"
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --startas $DAEMON
log_end_msg $?
}
do_stop () {
log_daemon_msg "Stopping system $DAEMON_NAME daemon"
start-stop-daemon --stop --pidfile $PIDFILE --retry 10
log_end_msg $?
}
 
case "$1" in
 
start|stop)
do_${1}
;;
 
restart|reload|force-reload)
do_stop
do_start
;;
 
status)
status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/$DEAMON_NAME {start|stop|restart|status}"
exit 1
;;
 
esac
exit 0
Review the top section in particular - everything before the "END CUSTOMISATION" line. Swapping those parts out with your own script/application should result in what you're after.

Once you have this script in place (My example is: /etc/init.d/moonlighter), do the following to set it to run on startup (again, replace "moonlighter" with what you called the init script - use [Tab] for auto-line-completion if you're not sure :D ):

Code: Select all

sudo chmod a+x /etc/init.d/moonlighter
sudo update-rc.d moonlighter enable

jvendryes
Posts: 3
Joined: Sun Jan 05, 2014 3:28 pm

Re: rc.local won't execute python mailer script (solved)

Sun Jan 05, 2014 3:41 pm

dalgibbard,

I've followed your solution. It works great when I reboot the Pi, but when I boot from a shutdown, the script fails to load. I am using a wifi adapter, not sure if that matters.

Here is my .py script:

Code: Select all

#!/usr/bin/python

import subprocess
import smtplib
import socket
from email.mime.text import MIMEText
import datetime

# Change to your own account information
to = 'redacted'
gmail_user = 'redacted'
gmail_password = 'redacted'
smtpserver = smtplib.SMTP('smtp.gmail.com', 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo
smtpserver.login(gmail_user, gmail_password)
today = datetime.date.today()

# Very Linux Specific
arg='ip route list'
p=subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE)
data = p.communicate()
split_data = data[0].split()
ipaddr = split_data[split_data.index('src')+1]
my_ip = 'Your ip is %s' %  ipaddr
msg = MIMEText(my_ip)
msg['Subject'] = 'IP For RaspberryPi on %s' % today.strftime('%b %d %Y')
msg['From'] = gmail_user
msg['To'] = to
smtpserver.sendmail(gmail_user, [to], msg.as_string())
smtpserver.quit()
Here is my .sh script:

Code: Select all

#!/bin/sh

### BEGIN INIT INFO
# Provides:          startup_mailer
# Required-Start:    $network $syslog
# Required-Stop:     $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Emails Raspberry Pi's IP address after boot
# Description:       Emails Raspberry Pi's IP address after boot 
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/home/pi/scripts
DAEMON=$DIR/startup_mailer.py
DAEMON_NAME=startup_mailer

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=root

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --startas $DAEMON
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in

    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
        ;;
    *)
        echo "Usage: /etc/init.d/$DEAMON_NAME {start|stop|restart|status}"
        exit 1
        ;;

esac
exit 0
Any advice?

dalgibbard
Posts: 9
Joined: Fri Jun 07, 2013 4:39 pm

Re: rc.local won't execute python mailer script (solved)

Sun Jan 05, 2014 4:56 pm

I made a small error in my first reply, I missed out setting the defaults for the init script; so, the "update-rc.d" lines should actually be (replacing "scriptname" with the actual name in the next steps):

Code: Select all

sudo update-rc.d scriptname defaults
sudo update-rc.d scriptname enable
At which point, you should see it appear in /etc/rc2.d/ - for example:

Code: Select all

find /etc/rc2.d/ -iname "*scriptname*"
returns:

Code: Select all

/etc/rc2.d/S03scriptname
Failing that, it's possible that your wireless configuration is being done outside of the normal "network" init (For example: when networking is instead defined in "/etc/rc.local" it takes place at "S05*", which will normally be after your own code). You may be able to work around this by renaming/moving your "S0Xscriptname" file in /etc/rc2.d/ to a number which pushes it to later in the init process; eg: S99scriptname.

That's a bit of a quick glance over it - so, apologies if it doesn't quite make sense! I can elaborate on anything you're unsure of.
I use this on two of my RasPi's at the moment; one with a WiPi adapter (configured in /etc/network/interfaces), and the other with wired ethernet.

Hope that helps!

jvendryes
Posts: 3
Joined: Sun Jan 05, 2014 3:28 pm

Re: rc.local won't execute python mailer script (solved)

Sun Jan 05, 2014 5:37 pm

So, just to clarify, I can just update the name and symlink with no issues you think?

Update
I set:

Code: Select all

# Required-Start: $all $syslog
# Required-Stop: $all $syslog
The manual https://wiki.debian.org/LSBInitScripts states:
$all facility supported by insserv to start a script after all the other scripts, at the end of the boot sequence. This only work for start ordering, not stop ordering. It is not possible to depend on a script which depend on $all.
Then I re-ran:

Code: Select all

sudo update-rc.d startup_mailer.sh defaults
which moved my script to the very last item in the list on /etc/rc2.d/:

Code: Select all

S04startup_mailer.sh -> ../init.d/startup_mailer.sh
My WiFi is also configured in configured in /etc/network/interfaces not in rc.local.

Long winded update but unfortunately nothing changed, still only works on "reboot" not on initial boot up.

jvendryes
Posts: 3
Joined: Sun Jan 05, 2014 3:28 pm

Re: rc.local won't execute python mailer script (solved)

Sun Jan 05, 2014 7:50 pm

Solved it. I set time.sleep(30) in my python script before everything executes and set Required-Start and Required-Stop back to $network.

The time.sleep(30) allows the Wifi portion to obtain its IP the first time before running the full script.

Good game!

dalgibbard
Posts: 9
Joined: Fri Jun 07, 2013 4:39 pm

Re: rc.local won't execute python mailer script (solved)

Sun Jan 05, 2014 8:49 pm

Peculiar, but at least it works!!

Return to “General programming discussion”

Who is online

Users browsing this forum: No registered users and 4 guests