I asked this question in January here on the platform and thought that the reason for my Pi crashing was the raspistill script I used. This turned out to be a false positive.
After some hassle and trying, I decided to give this issue another go and completely re-setup my RPi with the latest
RASPBIAN JESSIE LITE released at 2016-03-18 and gave it another try about 20 hours ago.
After about 12 hours of operation my RPi hung up / crashed again and only a hard reboot (power cut) could fix it.
Side info, the RPi is used for weather tracking + timelapsing. It gathers weather data from BMP085, DS18b20 and DHT22 sensors. Images are taken with the Raspberry Pi Camera module rev 1.3.
To my setup:
Raspbery PI model B
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 8.0 (jessie)
Release: 8.0
Codename: jessie
Linux carbon 4.1.19+ #858 Tue Mar 15 15:52:03 GMT 2016 armv6l GNU/Linux
root@hostname ~ # python --version
Python 2.7.9
root@hostname ~ # python3 --version
Python 3.4.2
Upon my Pi crashing I get this message in my kern.log file.
As one can easily see, the crash seems to be caused by my weatherPi script which is called every minute via a cronjob. But why?
This is my script:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This software is used to gather basic environmennt data from sensors
# connected to the Rapsberry Pi Model B. The gathered data is stored into
# MySQL database and printed to the console.
import os
import sys
import re
import Adafruit_DHT
import Adafruit_BMP.BMP085 as BMP085
import MySQLdb
import time
# make sure script is run as root
euid = os.geteuid()
if euid != 0:
print('Script not started as root. Running sudo...')
args = ['sudo', sys.executable] + sys.argv + [os.environ]
# the next line replaces the currently-running process with the sudo
os.execlpe('sudo', *args)
# create timestamp
timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
print('Gathering data...')
# grab humidity data from DHT22 sensor
sensor = 22
pin = 4
humidity, temperature_DHT22 = Adafruit_DHT.read_retry(sensor, pin)
# grab barometric data
sensor = BMP085.BMP085()
temperature_bmp9985 = sensor.read_temperature()
pressure_bmp9985 = (sensor.read_pressure()/100)
# grab outside temperature from ds18b20
f = open('/sys/bus/w1/devices/28-00043c9677ff/w1_slave', 'r')
lines = f.read()
match = re.search('t=(-?[0-9]+)', lines)
temperature_18b20 = (float(match.group(1))/1000)
# grab cpu temperature
cpuTempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
cpu_temp = float(cpuTempFile.read())/1000
cpuTempFile.close()
# calculate aproximate dew point
DewPoint = ((humidity / 100) ** 0.125) * (112 + 0.9 * temperature_18b20) + (0.1 * temperature_18b20) - 112
print('Opening database connection')
# connecting to MySQL database and creating cursor
# all queries are executed by the cursor
db = MySQLdb.connect(host="HOST", user="USER", passwd="PASSWORD", db="DATABASE")
cur = db.cursor()
print('Preparing SQL statement')
sql = (('INSERT INTO `weather_data` (`t_out`, `t_out_wall`, `t_case`, `t_cpu`, `humidity`, `pressure`, `dewpoint`) VALUES ({:.2f}, {:.1f}, {:.2f}, {:.2f}, {:.2f}, {:.0f}, {:.2f});').format(temperature_18b20, temperature_DHT22, temperature_bmp9985, cpu_temp, humidity, pressure_bmp9985, DewPoint))
print('Executing SQL statement')
cur.execute(sql)
print('Commiting SQL statement')
db.commit()
print('Closing database connection')
db.close
print('Acquired data:')
print(timestamp)
print('temperature_18b20 = {:0.2f} °C').format(temperature_18b20)
print('temperature_dht22 = {:0.1f} °C').format(temperature_DHT22)
print('temperature_bmp9985 = {:0.2f} °C').format(temperature_bmp9985)
print('temperature_cpu = {:0.2f} °C').format(cpu_temp)
print('humidity_dht22 = {:0.1f}%').format(humidity)
print('pressure_bmp9985 = {:0.0f} hPa').format(pressure_bmp9985)
print('dew_point = {:.2f} °C').format(DewPoint)
This is the crontab line I use (as root):
# gather weather data and commit to database
* * * * * /usr/local/bin/weatherPi
My questions are:
- What exactly does take up all the RAM?
- Why is the RAM not freed up after executing the script?
- How can I resolve the issue?
Additional info:
I already tried setting a timeout for the weatherPi script I use in cron, so if the script ran longer than 10 seconds, it would be killed with signal 9. This made no difference, whatsoever.
The Pi runs overclocked at Turbo, but this makes no difference to the crashes (tried several settings).
If any other information is needed, please let me know. I don't know any further on how to debug this issue.
EDIT:
After updating my code like the following the script seems to not close anymore. First tests (with same conditions above) crashed the Pi within an hour.
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
# This software is used to gather basic environmennt data
# with the Rapsberry Pi Model B. This software was sepecifically
# designed for one single system
import os
import sys
import re
import Adafruit_DHT
import Adafruit_BMP.BMP085 as BMP085
import MySQLdb
import time
# make sure script is run as root
euid = os.geteuid()
if euid != 0:
print('Script not started as root. Running sudo...')
args = ['sudo', sys.executable] + sys.argv + [os.environ]
# the next line replaces the currently-running process with the sudo
os.execlpe('sudo', *args)
# create timestamp
timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
print('Gathering data...')
# grab humidity data from DHT22 sensor
sensor = 22
pin = 4
humidity, temperature_DHT22 = Adafruit_DHT.read_retry(sensor, pin)
# grab barometric data
sensor = BMP085.BMP085()
temperature_bmp9985 = sensor.read_temperature()
pressure_bmp9985 = (sensor.read_pressure()/100)
# grab outside temperature from ds18b20
f = open('/sys/bus/w1/devices/28-00043c9677ff/w1_slave', 'r')
lines = f.read()
f.close()
match = re.search('t=(-?[0-9]+)', lines)
temperature_18b20 = (float(match.group(1))/1000)
# grab cpu temperature
cpuTempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
cpu_temp = float(cpuTempFile.read())/1000
cpuTempFile.close()
# calculate aproximate dew point
DewPoint = ((humidity / 100) ** 0.125) * (112 + 0.9 * temperature_18b20) + (0.1 * temperature_18b20) - 112
print('Opening database connection')
# connecting to MySQL database and creating cursor
# all queries are executed by the cursor
db = MySQLdb.connect(host="HOST", user="USER", passwd="PASSWORD", db="DATABASE")
cur = db.cursor()
print('Preparing SQL statement')
sql = (('INSERT INTO `weather_data` (`t_out`, `t_out_wall`, `t_case`, `t_cpu`, `humidity`, `pressure`, `dewpoint`) VALUES ({:.2f}, {:.1f}, {:.2f}, {:.2f}, {:.2f}, {:.0f}, {:.2f});').format(temperature_18b20, temperature_DHT22, temperature_bmp9985, cpu_temp, humidity, pressure_bmp9985, DewPoint))
print('Executing SQL statement')
cur.execute(sql)
print('Commiting SQL statement')
db.commit()
print('Closing database connection')
cur.close()
db.close()
print('Acquired data:')
print(timestamp)
print('temperature_18b20 = {:0.2f} °C').format(temperature_18b20)
print('temperature_dht22 = {:0.1f} °C').format(temperature_DHT22)
print('temperature_bmp9985 = {:0.2f} °C').format(temperature_bmp9985)
print('temperature_cpu = {:0.2f} °C').format(cpu_temp)
print('humidity_dht22 = {:0.1f}%').format(humidity)
print('pressure_bmp9985 = {:0.0f} hPa').format(pressure_bmp9985)
print('dew_point = {:.2f} °C').format(DewPoint)
Asked by tac:
Output of cat /sys/bus/w1/devices/28-00043c9677ff/w1_slave
56 00 55 00 7f ff 0c 10 7b : crc=7b YES
56 00 55 00 7f ff 0c 10 7b t=5375
This is just the temperature reading of the ds18b20 I2C temperature sensor on the bus.
Update 24.03.2016:
After using the suggested fixes from @tac all seemed to work fine for about 24 hours. But suddenly the RPi crashed again with the same kern.log which indicated that there was a mass of my weatherPi scripts running.
My guess is that the script starts hanging if the database connection cannot be established. From the Python MySQL docs I found that you can set a timeout for MySQLdb.connect. I added a 15 second timeout for testing purposes.
MySQLdb.connect(host="HOST", user="USER", passwd="PASSWORD", db="DATABASE", connect_timeout=15)
Another change that I made was to add a killall to the crontab, to assure that all remaining scripts are stopped before running a new one:
# gather weather data and commit to database
* * * * * killall weatherPi && /usr/local/bin/weatherPi
Of course the connection timeout is currently redundant because of the prefixed killall. I currently want to see if this helps at all. After some testing of about 48 hours I will remove this command again and try out my connection timeout solution solely
/sys/bus/w1/devices/28-00043c9677ff/w1_slave? Just a few numbers?