Commit 8afdb5e31132beed3c0a9b5641314c33c16d3a7c
1 parent
3e330c37
added Raspberry Pi CPU temperature reading
please note: CLI change: now need to specify which device to read! Documentation updated accordingly
Showing
2 changed files
with
140 additions
and
94 deletions
README.md
... | ... | @@ -25,7 +25,7 @@ This repository contains the following scripts: |
25 | 25 | * [check_otp](#check_otp) |
26 | 26 | plugin to monitor PrivacyIDEA (and LinOTP) OTP validation |
27 | 27 | * [check_temperature](#check_temperature) |
28 | - plugin to monitor the temperature of a 1-wire sensor on a RaspberryPi | |
28 | + plugin to monitor the CPU temperature of a RaspberryPi or that of a DS18b20 1-wire sensor on a RaspberryPi | |
29 | 29 | * [nagiosstatus](#nagiosstatus) |
30 | 30 | CGI-BIN script to report the status of nagios (to monitor nagios itself) |
31 | 31 | |
... | ... | @@ -237,15 +237,16 @@ define service { |
237 | 237 | |
238 | 238 | <a name=check_temperature>plugins/check_temperature</a> |
239 | 239 | ------------------------------------------------------- |
240 | -Plugin (check) to monitor monitor the temperature using a sensor connected to a | |
241 | -RaspberryPi. This implementation is specifically for the DS18B20 1-wire | |
242 | -temperature sensor. Other methods and interfaces can be plugged in easily (just | |
243 | -raise a request or provide a patch). For information on how to connect sensor | |
244 | -to the RaspberryPi and to get it working please see [this Adafruit tutorial]( | |
240 | +Plugin (check) to monitor monitor the Raspberry Pi CPU temperature or that of a | |
241 | +temperature sensor connected to a RaspberryPi. This implementation currently | |
242 | +supports the DS18B20 1-wire temperature sensor. Other methods and interfaces can | |
243 | +be plugged in easily (just raise a request or provide a patch). For information | |
244 | +on how to connect sensor to the RaspberryPi and to get it working please see | |
245 | +[this Adafruit tutorial]( | |
245 | 246 | https://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing). |
246 | 247 | |
247 | -To enable the 1-wire interface support on the RaspberryPi one can use the | |
248 | -command: | |
248 | +No setup is required to read the CPU temperature. To enable the 1-wire interface | |
249 | +support on the RaspberryPi one can use the command: | |
249 | 250 | ~~~ |
250 | 251 | sudo raspi-config nonint do_onewire 0 |
251 | 252 | ~~~ |
... | ... | @@ -256,32 +257,46 @@ Installation for is straightforward, after installing the script on the server |
256 | 257 | add the following to your Nagios `commands.cmd` configuration file: |
257 | 258 | |
258 | 259 | ~~~ |
260 | +# 'check_cpu_temperature' command definition to monitor CPU temperature in C | |
261 | +# parameters: warning (ARG1) and critical (ARG2) temperature in Celcius | |
262 | +define command { | |
263 | + command_name check_temperature | |
264 | + command_line [install_path]/plugins/check_temperature -w $ARG1$ -c $ARG2$ rpi_cpu | |
265 | +} | |
266 | + | |
267 | +# 'check_cpu_ftemperature' command definition to monitor CPU temperature in F | |
268 | +# parameters: warning (ARG1) and critical (ARG2) temperature in Celcius | |
269 | +define command { | |
270 | + command_name check_temperature | |
271 | + command_line [install_path]/plugins/check_temperature -F -w $ARG1$ -c $ARG2$ rpi_cpu | |
272 | +} | |
273 | + | |
259 | 274 | # 'check_temperature' command definition to monitor a single temperature in C |
260 | 275 | # parameters: warning (ARG1) and critical (ARG2) temperature in Celcius |
261 | 276 | define command { |
262 | 277 | command_name check_temperature |
263 | - command_line [install_path]/plugins/check_temperature -w $ARG1$ -c $ARG2$ | |
278 | + command_line [install_path]/plugins/check_temperature -w $ARG1$ -c $ARG2$ w1_ds18b20 | |
264 | 279 | } |
265 | 280 | |
266 | 281 | # 'check_ftemperature' command definition to monitor a single temperature in F |
267 | 282 | # parameters: warning (ARG1) and critical (ARG2) temperature in Farenheit |
268 | 283 | define command { |
269 | 284 | command_name check_ftemperature |
270 | - command_line [install_path]/plugins/check_temperature -F -w $ARG1$ -c $ARG2$ | |
285 | + command_line [install_path]/plugins/check_temperature -F -w $ARG1$ -c $ARG2$ w1_ds18b20 | |
271 | 286 | } |
272 | 287 | |
273 | 288 | # 'check_temperature_sensor' command definition to monitor a single temperature in C |
274 | 289 | # parameters: sensor serial (ARG1), warning (ARG2) and critical (ARG3) temperature in Celcius |
275 | 290 | define command { |
276 | 291 | command_name check_temperature_sensor |
277 | - command_line [install_path]/plugins/check_temperature -s $ARG1$ -w $ARG2$ -c $ARG3$ | |
292 | + command_line [install_path]/plugins/check_temperature -w $ARG2$ -c $ARG3$ w1_ds18b20 -s $ARG1$ | |
278 | 293 | } |
279 | 294 | |
280 | 295 | # 'check_ftemperature_sensor' command definition to monitor a single temperature in F |
281 | 296 | # parameters: sensor serial (ARG1), warning (ARG2) and critical (ARG3) temperature in Farenheit |
282 | 297 | define command { |
283 | 298 | command_name check_ftemperature_sensor |
284 | - command_line [install_path]/plugins/check_temperature -F -s $ARG1$ -w $ARG2$ -c $ARG3$ | |
299 | + command_line [install_path]/plugins/check_temperature -F -w $ARG2$ -c $ARG3$ w1_ds18b20 -s $ARG1$ | |
285 | 300 | } |
286 | 301 | |
287 | 302 | ~~~ |
... | ... | @@ -290,6 +305,14 @@ Make sure to replace `[install_path]/plugins` with the location of the script. |
290 | 305 | To use the it define a service check like below: |
291 | 306 | |
292 | 307 | ~~~ |
308 | +# check RaspberryPi CPU temperature in Celcius | |
309 | +define service { | |
310 | + host hostname.mydomain.tld | |
311 | + service_description CPU Temperature | |
312 | + check_command check_cpu_temperature!55!75 | |
313 | + use generic-service | |
314 | +} | |
315 | + | |
293 | 316 | # check temperature in Celcius using a DS18B20 sensor connected to a RaspberryPi |
294 | 317 | define service { |
295 | 318 | host hostname.mydomain.tld |
... | ... | @@ -298,7 +321,6 @@ define service { |
298 | 321 | use generic-service |
299 | 322 | } |
300 | 323 | |
301 | - | |
302 | 324 | # check temperature with DS18B20 sensor 0000a31ea3de connected to a RaspberryPi |
303 | 325 | define service { |
304 | 326 | host hostname.mydomain.tld |
... | ... | @@ -340,3 +362,4 @@ General Public License for more details. |
340 | 362 | |
341 | 363 | You should have received a copy of the GNU General Public License along with |
342 | 364 | this program. If not, download it from <http://www.gnu.org/licenses/>. |
365 | + | |
... | ... |
plugins/check_temperature
... | ... | @@ -2,10 +2,10 @@ |
2 | 2 | # |
3 | 3 | # check_temperature - Nagios temperature check for DS18B20 sensor on RaspberryPi |
4 | 4 | # |
5 | -# Version 1.0, latest version, documentation and bugtracker available at: | |
5 | +# Version 1.1, latest version, documentation and bugtracker available at: | |
6 | 6 | # https://gitlab.lindenaar.net/scripts/nagios-plugins |
7 | 7 | # |
8 | -# Copyright (c) 2016 Frederik Lindenaar | |
8 | +# Copyright (c) 2017 Frederik Lindenaar | |
9 | 9 | # |
10 | 10 | # This script is free software: you can redistribute and/or modify it under the |
11 | 11 | # 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, \ |
27 | 27 | import logging |
28 | 28 | |
29 | 29 | # Constants (no need to change but allows for easy customization) |
30 | -VERSION="1.0" | |
30 | +VERSION="1.1" | |
31 | 31 | PROG_NAME=splitext(basename(__file__))[0] |
32 | 32 | PROG_VERSION=PROG_NAME + ' ' + VERSION |
33 | 33 | SENSOR_SCALE=1000 |
34 | -SENSOR_DEV_DIR = '/sys/bus/w1/devices/' | |
35 | -SENSOR_DEV_PREFIX = '28-' | |
36 | -SENSOR_DEV_SUFFIX = '/w1_slave' | |
37 | -SENSOR_READ_RETRIES=10 | |
34 | +W1_SENSOR_DEV_DIR = '/sys/bus/w1/devices/' | |
35 | +W1_SENSOR_DEV_PREFIX = '28-' | |
36 | +W1_SENSOR_DEV_SUFFIX = '/w1_slave' | |
37 | +W1_SENSOR_READ_RETRIES=10 | |
38 | +CPU_SENSOR_DEV = '/sys/class/thermal/thermal_zone0/temp' | |
38 | 39 | |
39 | 40 | LOG_FORMAT='%(levelname)s - %(message)s' |
40 | 41 | LOG_FORMAT_FILE='%(asctime)s - ' + LOG_FORMAT |
... | ... | @@ -97,64 +98,21 @@ def isempty(string): |
97 | 98 | return string is None or len(string) == 0 |
98 | 99 | |
99 | 100 | |
100 | -def parse_args(): | |
101 | - """Parse command line and get parameters from environment, if present""" | |
102 | - | |
103 | - # Setup argument parser, the workhorse gluing it all together | |
104 | - parser = ArgumentParser( | |
105 | - epilog='(*) by default the script will look for the first device that ' | |
106 | - 'matches %s* in %s, if multiple entries are found -s or -f must ' | |
107 | - 'be used to specify which sensor to read.' % | |
108 | - (SENSOR_DEV_PREFIX, SENSOR_DEV_DIR), | |
109 | - description='Nagios check plugin for 1-wire temp. sensor on RaspberryPi' | |
110 | - ) | |
111 | - parser.add_argument('-V', '--version',action="version",version=PROG_VERSION) | |
112 | - | |
113 | - pgroup = parser.add_mutually_exclusive_group(required=False) | |
114 | - pgroup.add_argument('-C', '--celcius', action='store_const', | |
115 | - dest='converter', const=CONVERT_CELCIUS, | |
116 | - help='measure, critical and warn values in Celcius ' | |
117 | - '(default)', default=CONVERT_CELCIUS) | |
118 | - pgroup.add_argument('-F', '--farenheit',action='store_const', | |
119 | - dest='converter', const=CONVERT_FARENHEIT, | |
120 | - help='measure, critical and warn values in Farenheit') | |
121 | - | |
122 | - parser.add_argument('-w', '--warn', type=float, | |
123 | - help='temperature for warning status') | |
124 | - parser.add_argument('-c','--critical', type=float, | |
125 | - help='temperature for critical status') | |
126 | - | |
127 | - parser.add_argument('-r', '--retries', type=int,default=SENSOR_READ_RETRIES, | |
128 | - help='number of times to retry reading sensor data when' | |
129 | - ' unstable (defaults to %d)' % SENSOR_READ_RETRIES) | |
130 | - | |
131 | - pgroup = parser.add_mutually_exclusive_group(required=False) | |
132 | - pgroup.add_argument('-s', '--serial', | |
133 | - help='(unique part of) temperature sensor serial (*)') | |
134 | - pgroup.add_argument('-f', '--file', | |
135 | - help='input file (or device) to obtain data from (*)') | |
136 | - | |
137 | - pgroup = parser.add_mutually_exclusive_group(required=False) | |
138 | - pgroup.add_argument('-q', '--quiet', default=logging.CRITICAL, | |
139 | - action=SetLogLevel, const=LOGGING_NONE, | |
140 | - help='quiet (no output, only exit with exit code)') | |
141 | - pgroup.add_argument('-v', '--verbose', help='more verbose output', | |
142 | - action=SetLogLevel, const=logging.INFO) | |
143 | - pgroup.add_argument('-d', '--debug', help='debug output (more verbose)', | |
144 | - action=SetLogLevel, const=logging.DEBUG) | |
145 | - | |
146 | - parser.add_argument('-l', '--logfile', action=SetLogFile, | |
147 | - help='send logging output to logfile') | |
148 | - | |
149 | - # parse arguments and post-process command line options | |
150 | - args = parser.parse_args() | |
101 | +def read_rpi_cpu_temp(args): | |
102 | + """Reads CPU temperature and converts it to desired unit, returns temperature""" | |
103 | + with open(args.file, 'r') as f: | |
104 | + lines = f.readlines() | |
105 | + logger.debug('Temperature sensor data read from %s: %s', f.name, lines) | |
151 | 106 | |
152 | - # if we got here all seems OK | |
153 | - return args | |
107 | + temp_read = int(lines[0]) | |
108 | + temp = args.converter[0](temp_read) | |
109 | + logger.debug('Temperature sensor value %d is %.2f%s', temp_read, | |
110 | + temp, args.converter[1]) | |
111 | + return temp, 1 | |
154 | 112 | |
155 | 113 | |
156 | -def get_sensor_device_filename(args, dev_dir=SENSOR_DEV_DIR, | |
157 | - prefix=SENSOR_DEV_PREFIX, suffix=SENSOR_DEV_SUFFIX): | |
114 | +def get_w1_sensor_device_filename(args, dev_dir=W1_SENSOR_DEV_DIR, | |
115 | + prefix=W1_SENSOR_DEV_PREFIX, suffix=W1_SENSOR_DEV_SUFFIX): | |
158 | 116 | """Auto-determine sensor datafile name (unless args.file is set)""" |
159 | 117 | if isempty(args.file): |
160 | 118 | search_pat = dev_dir + ('/' if dev_dir[-1]!='/' else '') |
... | ... | @@ -180,23 +138,19 @@ def get_sensor_device_filename(args, dev_dir=SENSOR_DEV_DIR, |
180 | 138 | return filename |
181 | 139 | |
182 | 140 | |
183 | -def read_sensor_raw(device_file): | |
184 | - """Reads the raw data from the sensor device file, returns array of lines""" | |
185 | - with open(device_file, 'r') as f: | |
186 | - lines = f.readlines() | |
187 | - logger.debug('Temperature sensor data read from %s: %s', f.name, lines) | |
188 | - return lines | |
189 | - | |
190 | - | |
191 | -def read_temp(device_file, converter=CONVERT_CELCIUS, maxretries=10): | |
141 | +def read_w1_temp(args): | |
192 | 142 | """Reads sensor data and converts it to desired unit, returns temperature""" |
193 | - lines = read_sensor_raw(device_file) | |
194 | - tries = 1 | |
195 | - while lines[0].strip()[-3:] != 'YES' and tries <= maxretries: | |
143 | + device_file = get_w1_sensor_device_filename(args) | |
144 | + lines=[ '' ] | |
145 | + tries = 0 | |
146 | + while tries <= args.retries and lines[0].strip()[-3:] != 'YES': | |
147 | + if tries > 0: | |
148 | + logger.warn('Temperature sensor data not stable, reading once more') | |
149 | + sleep(0.2) | |
196 | 150 | tries += 1 |
197 | - sleep(0.2) | |
198 | - logger.warn('Temperature sensor data not stable, reading once more') | |
199 | - lines = read_temp_raw(device_file) | |
151 | + with open(device_file, 'r') as f: | |
152 | + lines = f.readlines() | |
153 | + logger.debug('Temperature sensor data read from %s: %s', f.name, lines) | |
200 | 154 | |
201 | 155 | if lines[0].strip()[-3:] != 'YES': |
202 | 156 | errmsg = 'no stable temperature sensor data after %d tries' % tries |
... | ... | @@ -206,15 +160,84 @@ def read_temp(device_file, converter=CONVERT_CELCIUS, maxretries=10): |
206 | 160 | errmsg = 'temperature sensor data format is not supported' |
207 | 161 | else: |
208 | 162 | temp_read = int(lines[1][equals_pos+2:]) |
209 | - temp = converter[0](temp_read) | |
163 | + temp = args.converter[0](temp_read) | |
210 | 164 | logger.debug('Temperature sensor value %d is %.2f%s', temp_read, |
211 | - temp, converter[1]) | |
165 | + temp, args.converter[1]) | |
212 | 166 | return temp, tries |
213 | 167 | |
214 | 168 | logger.critical(errmsg) |
215 | 169 | raise ValueError(errmsg) |
216 | 170 | |
217 | 171 | |
172 | +def parse_args(): | |
173 | + """Parse command line and get parameters from environment, if present""" | |
174 | + | |
175 | + # Setup argument parser, the workhorse gluing it all together | |
176 | + parser = ArgumentParser( | |
177 | + epilog='(*) by default the script will look for the first device that ' | |
178 | + 'matches %s* in %s, if multiple entries are found -s or -f must ' | |
179 | + 'be used to specify which sensor to read.' % | |
180 | + (W1_SENSOR_DEV_PREFIX, W1_SENSOR_DEV_DIR), | |
181 | + description='Nagios check plugin for 1-wire temp. sensor on RaspberryPi' | |
182 | + ) | |
183 | + parser.add_argument('-V', '--version',action="version",version=PROG_VERSION) | |
184 | + | |
185 | + pgroup = parser.add_mutually_exclusive_group(required=False) | |
186 | + pgroup.add_argument('-C', '--celcius', action='store_const', | |
187 | + dest='converter', const=CONVERT_CELCIUS, | |
188 | + help='measure, critical and warn values in Celcius ' | |
189 | + '(default)', default=CONVERT_CELCIUS) | |
190 | + pgroup.add_argument('-F', '--farenheit',action='store_const', | |
191 | + dest='converter', const=CONVERT_FARENHEIT, | |
192 | + help='measure, critical and warn values in Farenheit') | |
193 | + | |
194 | + parser.add_argument('-w', '--warn', type=float, | |
195 | + help='temperature for warning status') | |
196 | + parser.add_argument('-c','--critical', type=float, | |
197 | + help='temperature for critical status') | |
198 | + | |
199 | + pgroup = parser.add_mutually_exclusive_group(required=False) | |
200 | + pgroup.add_argument('-q', '--quiet', default=logging.CRITICAL, | |
201 | + action=SetLogLevel, const=LOGGING_NONE, | |
202 | + help='quiet (no output, only exit with exit code)') | |
203 | + pgroup.add_argument('-v', '--verbose', help='more verbose output', | |
204 | + action=SetLogLevel, const=logging.INFO) | |
205 | + pgroup.add_argument('-d', '--debug', help='debug output (more verbose)', | |
206 | + action=SetLogLevel, const=logging.DEBUG) | |
207 | + | |
208 | + parser.add_argument('-l', '--logfile', action=SetLogFile, | |
209 | + help='send logging output to logfile') | |
210 | + | |
211 | + subparser = parser.add_subparsers(title='Supported temperature sensors') | |
212 | + | |
213 | + cpuparser = ArgumentParser(add_help=False) | |
214 | + cpuparser.add_argument('-f', '--file', default=CPU_SENSOR_DEV, | |
215 | + help='input file (or device) to obtain data from' | |
216 | + ' (defaults to %s)' % CPU_SENSOR_DEV) | |
217 | + cmdparser = subparser.add_parser('rpi_cpu', parents=[cpuparser], | |
218 | + help='read built-in Raspberry Pi CPU temperature') | |
219 | + cmdparser.set_defaults(func=read_rpi_cpu_temp, cmdparser=cmdparser, retries=0) | |
220 | + | |
221 | + w1parser = ArgumentParser(add_help=False) | |
222 | + pgroup = w1parser.add_mutually_exclusive_group(required=False) | |
223 | + pgroup.add_argument('-s', '--serial', | |
224 | + help='(unique part of) temperature sensor serial (*)') | |
225 | + pgroup.add_argument('-f', '--file', | |
226 | + help='input file (or device) to obtain data from (*)') | |
227 | + w1parser.add_argument('-r', '--retries', type=int,default=W1_SENSOR_READ_RETRIES, | |
228 | + help='number of times to retry reading sensor data when' | |
229 | + ' unstable (defaults to %d)' % W1_SENSOR_READ_RETRIES) | |
230 | + cmdparser = subparser.add_parser('w1_ds18b20', parents=[w1parser], | |
231 | + help='read 1-wire connected DS18b20 sensor') | |
232 | + cmdparser.set_defaults(func=read_w1_temp, cmdparser=cmdparser) | |
233 | + | |
234 | + # parse arguments and post-process command line options | |
235 | + args = parser.parse_args() | |
236 | + | |
237 | + # if we got here all seems OK | |
238 | + return args | |
239 | + | |
240 | + | |
218 | 241 | def nagios_exit(status, message, data=None): |
219 | 242 | """exit 'nagios-style', print status and message followed by perf. data""" |
220 | 243 | if logger.isEnabledFor(logging.CRITICAL): |
... | ... | @@ -239,8 +262,7 @@ if __name__ == '__main__': |
239 | 262 | |
240 | 263 | try: |
241 | 264 | starttime = time() |
242 | - devicefile = get_sensor_device_filename(args) | |
243 | - temperature, tries = read_temp(devicefile, args.converter, args.retries) | |
265 | + temperature, tries = args.func(args) | |
244 | 266 | endtime = time() |
245 | 267 | |
246 | 268 | except (KeyboardInterrupt) as e: |
... | ... | @@ -270,3 +292,4 @@ if __name__ == '__main__': |
270 | 292 | ('retries', [ tries-1, None, args.retries, 0, None ]), |
271 | 293 | ('checktime', [ '%fs' % elapse, None, None, 0, None]) |
272 | 294 | ]) |
295 | + | |
... | ... |