2

I have written a python program that continuously parses my current IP and emails it to me if it changes that I want to begin running as soon as the computer boots up: /home/pi/sendIP.py

#note that unnecessary comments and sensitive information have been stripped
#assume this code works as intended
import smtplib
import os
import re
import time
def mail(message): try: server = smtplib.SMTP('smtp.gmail.com', 587) server.ehlo() server.starttls() server.login('from_email', 'password') server.sendmail('from_email', 'to_email', '\nIP: ' + str(message)) server.close() return True except: return False
def getStringIP(): try: IP = re.search(r'((?:\d{1,3}.){3}\d{1,3})', os.popen('hostname -I').read()).group(1) return IP except: return "null"
ip = ""
while(True): try: newIP = getStringIP() while(newIP == "null"): time.sleep(1) newIP = getStringIP() if(ip == newIP): time.sleep(1) else: ip = newIP while(not mail(ip)): time.sleep(0.5) time.sleep(1) except: time.sleep(2)
This file is run by /home/pi/sendIP.sh
#!/bin/bash
echo "calling sendIP.py"
/usr/bin/python3 /home/pi/sendIP.py&
echo "called in separate process"

sendIP.sh is in turn called by sendIP.service when the service is started manually or on bootup. If I call sendIP.sh directly by doing sudo bash sendIP.sh in a terminal window, it works perfectly and I receive an email with my current local IP. If, however, I do sudo systemctl start sendIP.service, it does not run the python file. Here is the .service file: /etc/systemd/system/sendIP.service

[Unit]
Description=Sends IP to my cellphone
After=all

[Service] ExecStart=/bin/bash /home/pi/sendIP.sh StandardOutput=inherit StandardInput=inherit User=pi
[Install] WantedBy=multi-user.target

And here is the result of sudo systemctl status sendIP.service after attempting to start the service:

● sendIP.service - Sends IP to my cellphone
   Loaded: loaded (/etc/systemd/system/sendIP.service; enabled)
   Active: inactive (dead) since Sun 2018-05-06 20:10:45 UTC; 1min 40s ago
  Process: 9830 ExecStart=/bin/bash /home/pi/sendIP.sh (code=exited, status=0/SUCCESS)
 Main PID: 9830 (code=exited, status=0/SUCCESS)

May 06 20:10:44 raspberrypi systemd[1]: Started Sends IP to my cellphone. May 06 20:10:45 raspberrypi bash[9830]: calling sendIP.py May 06 20:10:45 raspberrypi bash[9830]: called in separate process

It looks like it runs, as it echoes the text from the .sh file, but I do not receive any email as I should... I tried using print() statements in my python file to see if it even begins execution, but it does not print anything to my terminal window—including the echo statements, which I can only see when I check the status of the service (I am using ssh to access it, I don't know if it opens another window and prints there but it shouldn't). Running sendIP.sh directly does print both echo statements in the .sh file and and any print statements in the python program to the console, even with the & character causing sendIP.py to execute in another process. I should admit that I do not really know what I am doing with the .system file configuration, that part is mostly just what I have pieced together from similar questions and responses. If anyone could help me out that would be great! Thank y'all so much!

Ingo
  • 42,961
  • 20
  • 87
  • 207

2 Answers2

3

To show how it works I have made a stripped down test script that simply sends an email every minute. Here is the script:

rpi ~$ cat >/home/pi/mySendMail.py <<EOF
#! /usr/bin/python3

import time
import smtplib

def mail(message):
    try:
        server = smtplib.SMTP('smtp.gmail.com', 587)
        server.ehlo()
        server.starttls()
        server.login('from_email', 'password')
        server.sendmail('from_email', 'to_email', str(message))
        server.close()
        return True
    except:
        return False

while(True):
    fh = open("/tmp/mySendMail.log","a")
    if(mail("hello world")):
        fh.write("sended email at "+time.asctime(time.gmtime())+"\n")
    else:
        fh.write("error sending email at "+time.asctime(time.gmtime())+"\n")
    fh.close()
    time.sleep(60)
EOF

Test it on the command line. You should get emails.

rpi ~$ chmod u+x mySendMail.py
rpi ~$ ./mySendMail.py
rpi ~$ cat /tmp/mySendMail.log
sended email at Thu May 10 00:43:14 2018
sended email at Thu May 10 00:44:14 2018
sended email at Thu May 10 00:45:14 2018

Terminate with <ctrl>C.

Now we make a service for this script. The only condition is that it can only start After network is up and running so we can send emails. For this we have the network-online.target [3]. Create the new service with:

rpi ~$ sudo systemctl edit --force --full mySendMail.service

Insert this text in the editor save it and quit the editor:

[Unit]
Description=My Send Mail Service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/mySendMail.py

[Install]
WantedBy=multi-user.target

Check the service, enable and start it:

rpi ~$ systemctl status mySendMail.service
● mySendMail.service - My Send Mail Service
   Loaded: loaded (/etc/systemd/system/mySendMail.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

rpi ~$ systemctl cat mySendMail.service
rpi ~$ sudo systemctl enable mySendMail.service
rpi ~$ sudo systemctl start mySendMail.service

Now you should receive every minute an email. Stop it with:

rpi ~$ sudo systemctl stop mySendMail.service

You can edit the service with:

rpi ~$ sudo systemctl edit --full mySendMail.service

Reboot your raspi and it will start sending emails after boot up.


references:
[1] man systemd.unit
[2] How To Use Systemctl to Manage Systemd Services and Units
[3] Running Services After the Network is up
[4] systemd bootup
[5] systemd System and Service

Ingo
  • 42,961
  • 20
  • 87
  • 207
0

This question is not Pi specific, and is a general Linux question, but probably wouldn't get a helpful response as asked on U&L

As I understand it you are trying to create a systemd service, which runs a bash script, which runs a python script, which in turn gets the output of a system command.

The objective seems to monitor if your IP address changes (why do you think it might?) and notify you of the IP address. Why you would want to do this, or even why you want to know the IP address is unclear, but it is possible.

The bash script contains a spurious '\' in the shebang and contains echo (which will do nothing - as if successful will be run by root). If you want output write to a log file.

The above step is unnecessary, python is a scripting language, so you could just run a python script with shebang #! /usr/bin/env python3, or better call python3 from your service.

The systemd service is unusual, to say the least. I am unsure what After=all means, but I am not a systemd expert, and writing systemd services is complex.

The python script is an endless loop which runs every few seconds. This is wasteful - if you want to do this you would be better to use crontab to run a script every few seconds, rather than the complex steps you are attempting.

Milliways
  • 62,573
  • 32
  • 113
  • 225