Continuous Python script and restart if ended - python

I am making a script that reads the output from a 433 MHz receiver over i2c on Arduino to an Raspberry Pi. I have tried to run start it from rc.local, but it seems like after a couple of days the script ends/stops/breaks/halts/is killed (?).
I have tried to run the following script from cron to determine if the runs or not and start the Python script if it has stopped. But it seems to not detect a running script and starts a new script every time it runs and so finally crashing the system.
#!/bin/bash
until <path to Python script>; do
sleep 1
done
exit(0)
I have also tried to replace the always true while statement with a statement that lets the script run for a minute and restart the script with cron each minute, but that also results in that the script does not end and a new process is started.
Do anyone have any idea of how I either can make the script stable or able to restart. I.e. Always running all time until infinity! :-)
Python script:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Run in correct folder
import os
os.system("<path to script-folder>")
import sys
import MySQLdb as mdb
from smbus import SMBus
import RPi.GPIO as GPIO
import datetime
import time
addr = 0x10
intPin = 4
bus = SMBus(1)
def readData():
val = bus.read_byte(addr)
raw = val << 24
val = bus.read_byte(addr)
raw = raw | (val << 16)
val = bus.read_byte(addr)
raw = raw | (val << 8)
val = bus.read_byte(addr)
raw = raw | val
# Tidstämpel
ts = time.time()
date = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
try:
con = mdb.connect('<server>', '<User>', '<password>', '<DB>')
con.autocommit(True)
cur = con.cursor()
cur.execute("INSERT INTO <DB statement>") # Data is stored as integers
except mdb.Error, e:
errorLog = open('<path to log>', 'a')
errorlog.write("Error %d: %s" % (e.args[0],e.args[1]) + "\n")
errorlog.close()
sys.exit(1)
finally:
if con:
cur.close()
con.close()
while True:
GPIO.setmode(GPIO.BCM)
GPIO.setup(intPin,GPIO.IN)
GPIO.wait_for_edge(intPin, GPIO.RISING)
readData()

use linux screen to run the python script it will always run in backend until you stop the script.
http://www.tecmint.com/screen-command-examples-to-manage-linux-terminals/

Consider using daemontools. It's small and will ensure your code runs...forever.

Related

Nagios NRPE is not reading custom python plugin that is running fine from the command line

I have created a custom plugin for NRPE in Python 3. The script runs as expected when I run it from the command line as root and when I run it as nagios user. (I had a problem before when the nagios user didn't have permissions, but I fixed this is the sudoers file). I have an Arduino Uno taking input from a wind sensor and outputting the speed as type float to the serial monitor. The python script on my Raspberry Pi (os similar to debian 9) is reading the serial output and determining if the speed is in a specific range and then exiting with the respective code. Here's the python script:
#!/usr/bin/python3
import serial
import sys
import time
port = '/dev/ttyACM0'
baud = 9600
ser = serial.Serial(port,baud)
time.sleep(1) #allow time to connect with serial
def read_sensor():
i = 0
MPH_list = [] #used to find average of wind speed
while i < 5:
try:
speed = ser.readline()
speed = speed.decode("utf-8")
MPH_list.append(float(speed))
i += 1
except:
print('Failed to read Serial Monitor')
sys.exit(3) #unknown exit status
avgMPH = sum(MPH_list) / len(MPH_list) #average wind speed
print("%.2f MPH | 'Wind Speed'=%.2f" % (avgMPH,avgMPH)) #speed | performance data
if avgMPH < float(sys.argv[1]):
exit_code = 0
elif avgMPH >= float(sys.argv[1]) and avgMPH < float(sys.argv[2]):
exit_code = 1
elif avgMPH >= float(sys.argv[2]):
exit_code = 2
else:
exit_code = 3
return exit_code
sys.exit(read_sensor())
When I have the code as above, I get the following response in Nagios:
But when I change from float(sys.argv[1]) to 1.00 it outputs correctly as:
I need to be able to use sys.argv[] so I can pass in arguments from Nagios.
For some reason it is always exiting with a '1'(warning) error code and never entering the if statement when run from the nagios server. When I run the program from the command line, it works perfect.
The output should look something like: 0.08 MPH | 'Wind Speed'=0.08 where everything after the pipe is ignored in Nagios because it goes to create the perf data graph.
Here are some other things that may help:
nrpe.cfg command defenition:
command[check_MPH]=/usr/bin/sudo /usr/local/nagios/libexec/check_MPH.py $ARG1$ $ARG2$
command line sent from nagios:
$USER1$/check_nrpe -H $HOSTADDRESS$ -t 30 -c $ARG1$ $ARG2$
where $ARG1$ is 'check_MPH' and $ARG2$ is -a'-w 1.00 -c 15.00'

snmpwalk with python scrypt

I tried to build a python script to get temperature from snmp sensor.
If I use this command line with a Linux terminal
snmpwalk 10.100.2.21 -On -v 1 -c public .1.3.6.1.4.1.28507.14.1.3.1.1.2.2
Output is correct :
.1.3.6.1.4.1.28507.14.1.3.1.1.2.2 = INTEGER: 225
In fact it return temperature :-) 22.5 °C
But I must use a python script :
#!/usr/bin/python
# -*- coding: latin-1 -*-
import netsnmp
#oid = '.1.3.6.1.4.1.28507.14.1.3.1.1.2.2'
oid = netsnmp.VarList(netsnmp.Varbind('.1.3.6.1.4.1.28507.14.1.3.1.1.2.2'))
print ("Hello !!!")
res = netsnmp.snmpwalk(oid, Version=1, DestHost='10.100.2.21', Community='public')
print res
I don't know why, my script return only :
"()"
Have you some ides ?
thanks
The constructs for netsnmp don't work that way. As far as I know, you need to open a snmp session before making queries.
I usually do:
session=netsnmp.Session(DestHost=myip, Version=2, Community='public', RemotePort=161)
Then you can check if you got a proper session:
if session:
continue
else:
print sys.exc_info()
exit(1)
Finally:
myoid=netsnmp.VarList('.1.3.6.1.4.1.28507.14.1.3.1.1.2.2')
res=snmp.walk(myoid)
for i in res:
print i
I am using a for loop, because you chose snmp.walk(), that could potentially return many rows of values. You could use snmp.get() instead

Raspberry Pi background program runs but doesnt work

SOLVED: For some reason making CRON run a bash script that runs the python script solved the problem.
I have a python script "temperature.py" which is an infinite loop that checks values from a GPIO pin, adds the values to a file which it uploads to google drive with "gdrive" and sometimes sends a mail using smtp. The script works perfectly if i run it from the SSH terminal ($ sudo python temperature.py) but it doesn't work at startup like i would want it to.
I'm using raspbian wheezy.
What I've done:
in /etc/rc.local:
#...
#...
sleep 10
python /home/pi/temperature.py&
exit 0
the pi boots normally and after i login using SSH and write:
...$ps aux
i get:
...
root 2357 1.4 1.9 10556 8836 ? S 21:11 0:12 python /home/pi/temperature.py
...
so I'm guessing it is running and it uses 1.4% CPU which is very little but almost all other processes use 0.0%. Since the program probably
It doesnt do anything however... my google drive is empty...
So it works if i run it from terminal as background but not if i run it from rc.local...
What I'm guessing :
it lacks some permission?
it must be something with rc.local... since it works perfectly from terminal
The result of
...$ls -l temperature.py
-rwxr-xr-x 1 root root 1927 Dec 12 21:10 temperature.py
...$ls -l /etc/rc.local
-rwxr-xr-x 1 root root 373 Dec 12 20:54 /etc/rc.local
I have tried staring it using cron ($sudo crontab -e) but it didn't work either.
Any ideas? I feel like I'm missing something obvious but since I'm very new to raspberry pi and linux stuff I can't find it on google.
The script temperature.py
#Made by Matthew Kirk
# Licensed under MIT License, see
# http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/temperature/LICENSE
#Adapted by me
import RPi.GPIO as GPIO
import time
import subprocess
import os
import commands
import sys
import smtplib
from email.mime.text import MIMEText
print 'TEMPERATURE LOGGER - M'
print ' '
#MAILER SETUP
to = '****#gmail.com'
gmail_user = '****#gmail.com'
gmail_password = '*****'
smtpserver = smtplib.SMTP('smtp.gmail.com',587)
#TEMP LOGGER GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7,GPIO.IN)
while True:
print 'fail'
if GPIO.input(7):
break
while GPIO.input(7):
pass
waitTime = 60
tempTreshold = 50
logFile = "/home/pi/tDat.csv"
while True:
dataFile = open(logFile,"a")
time_1 = time.time()
tFile = open("/sys/bus/w1/devices/28-011582ac5dff/w1_slave")
text = tFile.read();
tFile.close();
tData = text.split("\n")[1].split(" ")[9]
temp = float(tData[2:])
temp = temp/1000
timeStamp = time.strftime("%d/%m/%Y %H:%M:%S")
dataFile.write(str(temp)+","+ timeStamp+ "\n")
dataFile.close()
file_ID = commands.getoutput('drive list | tail -n +2 | head -1 | awk \'{print $1;}\' ')
cmd = 'drive delete --id '+file_ID
os.system( cmd )
cmd = 'drive upload --file '+logFile
os.system( cmd )
# MAIL IF TEMP TOO LOW
if temp < tempTreshold:
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo()
smtpserver.login(gmail_user,gmail_password)
msg = MIMEText('The temperature in Branten, {}C, is below {} degrees C!!!'.format(temp,tempTreshold)+'\n'+'Recorded$
msg['Subject'] = 'Branten Temperature Warning'
msg['From'] = gmail_user
msg['To'] = to
smtpserver.sendmail(gmail_user,[to],msg.as_string())
smtpserver.quit()
sys.exit()
and the CRON:
* * * * * python /home/pi/temperature.py
Consider revising your code to not use an infinate loop.
Read about Linux CRON jobs. CRON is a service that will execute your program or script on a schedule (properly). EDIT: it is installed by default on most linux distros including Rasbian.
Some good examples
Maybe nohup helps?
nohup python /home/pi/temperature.py&

Python script not runnig on boot - raspberry

I made a python script on my raspberry - /home/pi/bin/script.py:
#!/usr/bin/python
from urllib2 import urlopen
from time import sleep
FILE = "publicip"
SITE = "http://ipecho.net/plain"
DELAY = 60 # seconds
def get_ip():
while True:
# wait for DELAY seconds
sleep(DELAY)
# get my current public ip
try:
ip = urlopen(SITE).read()
except IOError:
continue
# compare with the one in file
file_value = open(FILE).read()
if ip != file_value: # if they are not equal
open(FILE, "w").write(ip) # update the ip in file
if __name__ == "__main__":
get_ip()
It's propose is to get my public ip and store it in a file.
I need this script run in a loop so it can update the file as soon
the ip changes.
If the power fail I want it to run when the raspberry restarts. So,
I updated the /etc/rc.local file:
#!/bin/sh -e
/home/pi/bin/script.py
exit 0
After that I used sudo reboot to restart the raspberry. I'm using PuTTY
from a windows computer to connect to the raspberry. After logging in again
I used ps -e | grep script.py to see if my script was runnig but it was
not. Then I runned the script manually and it worked!
What would you do to solve this problem?
An alternative for running in the cron or init, it to use a userspace monitor.
This tutorial is great showing supervisor.
It is really easy to use.
apt-get install supervisor
service supervisor restart
add to /etc/supervisor/conf.d/ip_update.conf
[program:ip_update]
command=/home/pi/bin/script.py
autostart=true
autorestart=true
stderr_logfile=/var/log/ip_update.err.log
stdout_logfile=/var/log/ip_update.out.log
and you can still use supervisorctl to manage it:
$ supervisorctl
> restart ip_update
First verify your script execution's permission, if it's have a execution permission. After that, you need use & after command of script in (runs to infinite loops), try:
#!/bin/sh
/home/pi/bin/script.py &
More details in raspbian documentation.
Your other option is to use cron
sudo crontab -e will open the crontab for you
you can set your script to run as often as you like and if you put in the entry:
#reboot /home/pi/bin/script.py
it should run during the boot sequence
other non numeric options are:
#yearly Run once a year, "0 0 1 1 *".
#annually (same as #yearly)
#monthly Run once a month, "0 0 1 * *".
#weekly Run once a week, "0 0 * * 0".
#daily Run once a day, "0 0 * * *".
#midnight (same as #daily)
#hourly Run once an hour, "0 * * * *"
The standard entry is:
# Minute Hour Day of Month Month Day of Week Command
0 * * * * /home/pi/bin/script.py
#Once an hour on the hour
* * * * * /home/pi/bin/script.py
#Every minute
Edit:
with reference to your comment, performing it with cron, means that you should take out the timing within your code, as that is what cron is doing. So you would end up up with something like:
#!/usr/bin/python
from urllib2 import urlopen
FILE = "publicip"
SITE = "http://ipecho.net/plain"
def get_ip():
try:
ip = urlopen(SITE).read()
except IOError:
continue
# compare with the one in file
file_value = open(FILE).read()
if ip != file_value: # if they are not equal
open(FILE, "w").write(ip) # update the ip in file
if __name__ == "__main__":
get_ip()
With reference to your existing code, I notice that you are never closing the file, just an endless loop of opening it with read and then opening it with write, I'm not sure quite how python will handle that offhand but it certainly isn't good practice.

Python pexpect won't work

I have a question about pexepct in Python.
What I wanna to do is, run my script at some time, and then stop it at some time.
Pexpect wont work like it should. I don't know what I'm doing wrong, so can you give me some advice on my code below?
#!/usr/bin/python
# -*- coding: utf-8 -*-
date = '2014-09-06'
start = '15:32'
stop = '16:30'
import pexpect, sys
string = 'at '+start+' '+date
child = pexpect.spawn(string)
child.expect('warning: commands will be executed using /bin/sh')
child.expect('at> ')
child.sendline('./run_script.py\n')
child.expect('at> ')
child.sendline('\^D\n')
print child.before
The problem is, when all commands send pexepct wont create a job.
Any advice should be great.
Here the way ctrl+d is sent is not valid. Even after sending ctrl+d, the script has to wait for couple of seconds for the at command to register the new job before closing the pexpect spawn object.
import pexpect
import sys
import time
prompt = "at>"
try:
conn = pexpect.spawn("at 14:30 2019-06-14")
conn.logfile = sys.stdout
conn.expect(prompt)
conn.sendline("touch /tmp/test.txt")
conn.expect(prompt)
conn.sendcontrol("d")
time.sleep(3)
conn.close()
except Exception as e:
print(e)
After executing the above code snippet, run the command 'atq' in the linux terminal to verify that job has been queued up.
# atq
52 Fri Jun 14 14:30:00 2019 a root

Categories

Resources