added Raspberry Pi CPU temperature reading

please note: CLI change: now need to specify which device to read!

Documentation updated accordingly
This commit is contained in:
2018-01-06 20:06:27 +01:00
parent 3e330c37e2
commit 8afdb5e311
2 changed files with 140 additions and 94 deletions

View File

@@ -2,10 +2,10 @@
#
# check_temperature - Nagios temperature check for DS18B20 sensor on RaspberryPi
#
# Version 1.0, latest version, documentation and bugtracker available at:
# Version 1.1, latest version, documentation and bugtracker available at:
# https://gitlab.lindenaar.net/scripts/nagios-plugins
#
# Copyright (c) 2016 Frederik Lindenaar
# Copyright (c) 2017 Frederik Lindenaar
#
# This script is free software: you can redistribute and/or modify it under the
# terms of version 3 of the GNU General Public License as published by the Free
@@ -27,14 +27,15 @@ from argparse import ArgumentParser as StandardArgumentParser, FileType, \
import logging
# Constants (no need to change but allows for easy customization)
VERSION="1.0"
VERSION="1.1"
PROG_NAME=splitext(basename(__file__))[0]
PROG_VERSION=PROG_NAME + ' ' + VERSION
SENSOR_SCALE=1000
SENSOR_DEV_DIR = '/sys/bus/w1/devices/'
SENSOR_DEV_PREFIX = '28-'
SENSOR_DEV_SUFFIX = '/w1_slave'
SENSOR_READ_RETRIES=10
W1_SENSOR_DEV_DIR = '/sys/bus/w1/devices/'
W1_SENSOR_DEV_PREFIX = '28-'
W1_SENSOR_DEV_SUFFIX = '/w1_slave'
W1_SENSOR_READ_RETRIES=10
CPU_SENSOR_DEV = '/sys/class/thermal/thermal_zone0/temp'
LOG_FORMAT='%(levelname)s - %(message)s'
LOG_FORMAT_FILE='%(asctime)s - ' + LOG_FORMAT
@@ -97,64 +98,21 @@ def isempty(string):
return string is None or len(string) == 0
def parse_args():
"""Parse command line and get parameters from environment, if present"""
def read_rpi_cpu_temp(args):
"""Reads CPU temperature and converts it to desired unit, returns temperature"""
with open(args.file, 'r') as f:
lines = f.readlines()
logger.debug('Temperature sensor data read from %s: %s', f.name, lines)
# Setup argument parser, the workhorse gluing it all together
parser = ArgumentParser(
epilog='(*) by default the script will look for the first device that '
'matches %s* in %s, if multiple entries are found -s or -f must '
'be used to specify which sensor to read.' %
(SENSOR_DEV_PREFIX, SENSOR_DEV_DIR),
description='Nagios check plugin for 1-wire temp. sensor on RaspberryPi'
)
parser.add_argument('-V', '--version',action="version",version=PROG_VERSION)
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('-C', '--celcius', action='store_const',
dest='converter', const=CONVERT_CELCIUS,
help='measure, critical and warn values in Celcius '
'(default)', default=CONVERT_CELCIUS)
pgroup.add_argument('-F', '--farenheit',action='store_const',
dest='converter', const=CONVERT_FARENHEIT,
help='measure, critical and warn values in Farenheit')
parser.add_argument('-w', '--warn', type=float,
help='temperature for warning status')
parser.add_argument('-c','--critical', type=float,
help='temperature for critical status')
parser.add_argument('-r', '--retries', type=int,default=SENSOR_READ_RETRIES,
help='number of times to retry reading sensor data when'
' unstable (defaults to %d)' % SENSOR_READ_RETRIES)
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('-s', '--serial',
help='(unique part of) temperature sensor serial (*)')
pgroup.add_argument('-f', '--file',
help='input file (or device) to obtain data from (*)')
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('-q', '--quiet', default=logging.CRITICAL,
action=SetLogLevel, const=LOGGING_NONE,
help='quiet (no output, only exit with exit code)')
pgroup.add_argument('-v', '--verbose', help='more verbose output',
action=SetLogLevel, const=logging.INFO)
pgroup.add_argument('-d', '--debug', help='debug output (more verbose)',
action=SetLogLevel, const=logging.DEBUG)
parser.add_argument('-l', '--logfile', action=SetLogFile,
help='send logging output to logfile')
# parse arguments and post-process command line options
args = parser.parse_args()
# if we got here all seems OK
return args
temp_read = int(lines[0])
temp = args.converter[0](temp_read)
logger.debug('Temperature sensor value %d is %.2f%s', temp_read,
temp, args.converter[1])
return temp, 1
def get_sensor_device_filename(args, dev_dir=SENSOR_DEV_DIR,
prefix=SENSOR_DEV_PREFIX, suffix=SENSOR_DEV_SUFFIX):
def get_w1_sensor_device_filename(args, dev_dir=W1_SENSOR_DEV_DIR,
prefix=W1_SENSOR_DEV_PREFIX, suffix=W1_SENSOR_DEV_SUFFIX):
"""Auto-determine sensor datafile name (unless args.file is set)"""
if isempty(args.file):
search_pat = dev_dir + ('/' if dev_dir[-1]!='/' else '')
@@ -180,23 +138,19 @@ def get_sensor_device_filename(args, dev_dir=SENSOR_DEV_DIR,
return filename
def read_sensor_raw(device_file):
"""Reads the raw data from the sensor device file, returns array of lines"""
with open(device_file, 'r') as f:
lines = f.readlines()
logger.debug('Temperature sensor data read from %s: %s', f.name, lines)
return lines
def read_temp(device_file, converter=CONVERT_CELCIUS, maxretries=10):
def read_w1_temp(args):
"""Reads sensor data and converts it to desired unit, returns temperature"""
lines = read_sensor_raw(device_file)
tries = 1
while lines[0].strip()[-3:] != 'YES' and tries <= maxretries:
device_file = get_w1_sensor_device_filename(args)
lines=[ '' ]
tries = 0
while tries <= args.retries and lines[0].strip()[-3:] != 'YES':
if tries > 0:
logger.warn('Temperature sensor data not stable, reading once more')
sleep(0.2)
tries += 1
sleep(0.2)
logger.warn('Temperature sensor data not stable, reading once more')
lines = read_temp_raw(device_file)
with open(device_file, 'r') as f:
lines = f.readlines()
logger.debug('Temperature sensor data read from %s: %s', f.name, lines)
if lines[0].strip()[-3:] != 'YES':
errmsg = 'no stable temperature sensor data after %d tries' % tries
@@ -206,15 +160,84 @@ def read_temp(device_file, converter=CONVERT_CELCIUS, maxretries=10):
errmsg = 'temperature sensor data format is not supported'
else:
temp_read = int(lines[1][equals_pos+2:])
temp = converter[0](temp_read)
temp = args.converter[0](temp_read)
logger.debug('Temperature sensor value %d is %.2f%s', temp_read,
temp, converter[1])
temp, args.converter[1])
return temp, tries
logger.critical(errmsg)
raise ValueError(errmsg)
def parse_args():
"""Parse command line and get parameters from environment, if present"""
# Setup argument parser, the workhorse gluing it all together
parser = ArgumentParser(
epilog='(*) by default the script will look for the first device that '
'matches %s* in %s, if multiple entries are found -s or -f must '
'be used to specify which sensor to read.' %
(W1_SENSOR_DEV_PREFIX, W1_SENSOR_DEV_DIR),
description='Nagios check plugin for 1-wire temp. sensor on RaspberryPi'
)
parser.add_argument('-V', '--version',action="version",version=PROG_VERSION)
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('-C', '--celcius', action='store_const',
dest='converter', const=CONVERT_CELCIUS,
help='measure, critical and warn values in Celcius '
'(default)', default=CONVERT_CELCIUS)
pgroup.add_argument('-F', '--farenheit',action='store_const',
dest='converter', const=CONVERT_FARENHEIT,
help='measure, critical and warn values in Farenheit')
parser.add_argument('-w', '--warn', type=float,
help='temperature for warning status')
parser.add_argument('-c','--critical', type=float,
help='temperature for critical status')
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('-q', '--quiet', default=logging.CRITICAL,
action=SetLogLevel, const=LOGGING_NONE,
help='quiet (no output, only exit with exit code)')
pgroup.add_argument('-v', '--verbose', help='more verbose output',
action=SetLogLevel, const=logging.INFO)
pgroup.add_argument('-d', '--debug', help='debug output (more verbose)',
action=SetLogLevel, const=logging.DEBUG)
parser.add_argument('-l', '--logfile', action=SetLogFile,
help='send logging output to logfile')
subparser = parser.add_subparsers(title='Supported temperature sensors')
cpuparser = ArgumentParser(add_help=False)
cpuparser.add_argument('-f', '--file', default=CPU_SENSOR_DEV,
help='input file (or device) to obtain data from'
' (defaults to %s)' % CPU_SENSOR_DEV)
cmdparser = subparser.add_parser('rpi_cpu', parents=[cpuparser],
help='read built-in Raspberry Pi CPU temperature')
cmdparser.set_defaults(func=read_rpi_cpu_temp, cmdparser=cmdparser, retries=0)
w1parser = ArgumentParser(add_help=False)
pgroup = w1parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('-s', '--serial',
help='(unique part of) temperature sensor serial (*)')
pgroup.add_argument('-f', '--file',
help='input file (or device) to obtain data from (*)')
w1parser.add_argument('-r', '--retries', type=int,default=W1_SENSOR_READ_RETRIES,
help='number of times to retry reading sensor data when'
' unstable (defaults to %d)' % W1_SENSOR_READ_RETRIES)
cmdparser = subparser.add_parser('w1_ds18b20', parents=[w1parser],
help='read 1-wire connected DS18b20 sensor')
cmdparser.set_defaults(func=read_w1_temp, cmdparser=cmdparser)
# parse arguments and post-process command line options
args = parser.parse_args()
# if we got here all seems OK
return args
def nagios_exit(status, message, data=None):
"""exit 'nagios-style', print status and message followed by perf. data"""
if logger.isEnabledFor(logging.CRITICAL):
@@ -239,8 +262,7 @@ if __name__ == '__main__':
try:
starttime = time()
devicefile = get_sensor_device_filename(args)
temperature, tries = read_temp(devicefile, args.converter, args.retries)
temperature, tries = args.func(args)
endtime = time()
except (KeyboardInterrupt) as e:
@@ -270,3 +292,4 @@ if __name__ == '__main__':
('retries', [ tries-1, None, args.retries, 0, None ]),
('checktime', [ '%fs' % elapse, None, None, 0, None])
])