Last active
August 29, 2015 13:56
-
-
Save tdack/9129944 to your computer and use it in GitHub Desktop.
DS18B20 1-wire data collection on Raspberry Pi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os, sys, glob, argparse | |
import ConfigParser | |
LOCATIONS = { 'rrd': '' | |
, 'graphs': '' | |
, 'sys_base': '/sys/bus/w1/devices/' | |
, 'config': '' | |
} | |
LOCATIONS['sys_devices'] = glob.glob(LOCATIONS['sys_base'] + '28*') | |
def main(): | |
global LOCATIONS | |
parser = argparse.ArgumentParser(description='Generate config file for reading DS18B20 temperatures') | |
parser.add_argument('-c', '--config' | |
, action='store' | |
, metavar='FILENAME' | |
, required=True | |
, help='Specifiy the configuration file to be used') | |
parser.add_argument('-g', '--graphs' | |
, action='store' | |
, metavar='FILENAME' | |
, required=True | |
, help='Specifiy the directory to store the graph files in') | |
parser.add_argument('-r', '--rrd' | |
, action='store' | |
, metavar='FILENAME' | |
, required=True | |
, help='Specifiy the RRD file to use') | |
if len(sys.argv) == 1: | |
parser.print_help() | |
return | |
args = parser.parse_args() | |
LOCATIONS['config'] = args.config | |
LOCATIONS['rrd'] = args.rrd | |
LOCATIONS['graphs'] = args.graphs if args.graphs[-1:] == '/' else args.graphs + '/' | |
config = ConfigParser.SafeConfigParser() | |
config.add_section('locations') | |
config.set('locations', 'graphs', LOCATIONS['graphs']) | |
config.set('locations', 'rrd', LOCATIONS['rrd']) | |
for index, sensor in enumerate(LOCATIONS['sys_devices']): | |
config.add_section(str(sensor[-4:])) | |
config.set(str(sensor[-4:]), 'ds', str('Temp Probe ' + sensor[-4:])) | |
config.set(str(sensor[-4:]), 'colour', str('#' + sensor[-6:])) | |
with open(LOCATIONS['config'], 'wb') as configfile: | |
config.write(configfile) | |
print 'Config file %s written', LOCATIONS['config'] | |
return | |
if __name__ == '__main__': | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os, sys, glob, argparse | |
import rrdtool | |
import ConfigParser | |
LOCATIONS = {} | |
SENSORS = {} | |
def read_config(): | |
global SENSORS | |
global LOCATIONS | |
config = ConfigParser.SafeConfigParser() | |
config.read(LOCATIONS['config']) | |
for s in config.sections(): | |
if s != 'locations': | |
SENSORS[s] = {} | |
for o in config.options(s): | |
SENSORS[s][o] = config.get(s, o) | |
else: | |
for o in config.options(s): | |
LOCATIONS[o] = config.get(s,o) | |
return | |
def main(): | |
global LOCATIONS | |
parser = argparse.ArgumentParser(description='Generate .rrd file for reading DS18B20 temperatures') | |
parser.add_argument('-c', '--config' | |
, action='store' | |
, metavar='FILENAME' | |
, required=True | |
, help='Specifiy the configuration file to be used') | |
if len(sys.argv) == 1: | |
parser.print_help() | |
return | |
args = parser.parse_args() | |
LOCATIONS['config'] = args.config | |
read_config() | |
data_sources = [] | |
for k, v in SENSORS.items(): | |
data_sources.append('DS:%s:GAUGE:600:U:U' % (v['ds'])) | |
rrdtool.create( LOCATIONS['rrd'], '--start', 'N', '--step', '300' | |
, data_sources | |
, 'RRA:AVERAGE:0.5:1:12' # 1 hr, 5 min resolution | |
, 'RRA:AVERAGE:0.5:1:144' # 12 hrs, 5 min resolution | |
, 'RRA:AVERAGE:0.5:1:288' # 1 day, 5 min resolution | |
, 'RRA:AVERAGE:0.5:3:672' # 7 days, 15 min resolution | |
, 'RRA:AVERAGE:0.5:12:720' # 30 days, 1 hr resolution | |
, 'RRA:AVERAGE:0.5:36:720' # 90 days, 3 hr resolution | |
, 'RRA:AVERAGE:0.5:288:365')# 1 year, 24 hr resolution | |
return | |
if __name__ == '__main__': | |
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[locations] | |
rrd=/pat/to/rrd_file.rrd | |
graphs=/path/to/graph_directory/ | |
[9ce0] | |
ds = shed | |
colour = #FFCC00 | |
[aab8] | |
ds = fridge | |
colour = #00CC00 | |
[5cc3] | |
ds = freezer | |
colour = #0033FF |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os, sys, datetime, re, glob, argparse | |
import rrdtool | |
import ConfigParser | |
LOCATIONS = { 'rrd': '' | |
, 'graphs': '' | |
, 'sys_base': '/sys/bus/w1/devices/' | |
, 'config': '' | |
} | |
LOCATIONS['sys_devices'] = glob.glob(LOCATIONS['sys_base'] + '28*') | |
SENSORS = {} | |
now = datetime.datetime.now() | |
def read_config(): | |
global SENSORS | |
global LOCATIONS | |
config = ConfigParser.SafeConfigParser() | |
config.read(LOCATIONS['config']) | |
for s in config.sections(): | |
if s != 'locations': | |
SENSORS[s] = {} | |
for o in config.options(s): | |
SENSORS[s][o] = config.get(s,o) | |
SENSORS[s]['value'] = 0 | |
else: | |
for o in config.options(s): | |
LOCATIONS[o] = config.get(s,o) | |
LOCATIONS['graphs'] = LOCATIONS['graphs'] if LOCATIONS['graphs'][-1:] == '/' else LOCATIONS['graphs'] + '/' | |
return | |
def graph_temps(): | |
GRAPH_DEFS = [] | |
LINE_DEFS = [] | |
# Common options for each graph, size, title, etc.. | |
GRAPH_OPTIONS = [ '--title', 'Temperatures' | |
, '--vertical-label', 'Celcius' | |
, '--width', '800' | |
, '--height', '200' | |
, '--slope-mode' | |
, '--pango-markup' | |
, '--imgformat', 'PNG' | |
, '--watermark', "%s" % ( now.strftime('Updated: %c') ) | |
] | |
# Header row for the legend and displayed measurements | |
LEGEND_HEADER = [ 'COMMENT:\t' | |
, 'COMMENT:\t<b> Last</b>' | |
, 'COMMENT:\t<b>Maximum</b>' | |
, 'COMMENT:\t<b>Average</b>' | |
, 'COMMENT:\t<b>Minimum</b>' | |
, 'COMMENT:\t<b>95th %</b>\l' | |
] | |
# generate line and legend items for each DS in the .rrd | |
for s, k in SENSORS.iteritems(): | |
GRAPH_DEFS.append('DEF:%s=%s:%s:AVERAGE' % (k['ds'], LOCATIONS['rrd'], k['ds'])) | |
LINE_DEFS.extend([ | |
'LINE2:%s%s:<b>%s</b>' % (k['ds'], k['colour'], '{:<10}'.format(k['ds'].title())) | |
, 'VDEF:%s_last=%s,LAST' % (k['ds'], k['ds']) | |
, 'VDEF:%s_max=%s,MAXIMUM' % (k['ds'], k['ds']) | |
, 'VDEF:%s_avg=%s,AVERAGE' % (k['ds'], k['ds']) | |
, 'VDEF:%s_min=%s,MINIMUM' % (k['ds'], k['ds']) | |
, 'VDEF:%s_pct=%s,95,PERCENT' % (k['ds'], k['ds']) | |
, 'GPRINT:%s_last:\t%%6.2lf' % (k['ds']) | |
, 'GPRINT:%s_max:\t%%6.2lf' % (k['ds']) | |
, 'GPRINT:%s_avg:\t%%6.2lf' % (k['ds']) | |
, 'GPRINT:%s_min:\t%%6.2lf' % (k['ds']) | |
, 'GPRINT:%s_pct:\t%%6.2lf\l' % (k['ds']) | |
]) | |
# Now we have all the parts to make an rrdgraph command | |
# Loop through and generate a graphe for each period | |
for schedule in ['hour', 'day', 'week', 'month', 'year']: | |
ret = rrdtool.graph("%s%s.png" % ( LOCATIONS['graphs'], schedule ) | |
, '--start', 'end-1%s' % ( schedule[0] ) | |
, GRAPH_OPTIONS | |
, GRAPH_DEFS | |
, LEGEND_HEADER | |
, LINE_DEFS, ) | |
return | |
def read_temps(): | |
# reads 1-wire DS18B20 temperature sensors and outputs options for rrdupdate | |
global SENSORS | |
DS_list = "" | |
value_list = "N:" | |
for index, sensor in enumerate(LOCATIONS['sys_devices']): | |
for k, v in SENSORS.items(): | |
if sensor[-4:] == k: | |
f = open(sensor + '/w1_slave', 'r') | |
lines = f.readlines() | |
f.close() | |
if lines[0].strip()[-3:] == 'YES': | |
v['value'] = float(lines[1][lines[1].find('t=')+2:])/1000.0 | |
return | |
def update_rrd(): | |
DS_list = '' | |
value_list = 'N:' | |
for k, v in SENSORS.items(): | |
DS_list += v['ds'] + ':' | |
value_list += str(v['value']) + ':' | |
DS_list = DS_list[:-1] | |
value_list = value_list[:-1] | |
rrdtool.update( LOCATIONS['rrd'], '--template', DS_list, value_list ) | |
return | |
def main(): | |
global LOCATIONS | |
base, ext = os.path.splitext(__file__) | |
parser = argparse.ArgumentParser(description='Read, store and graph temperatures from 1-wire sensors') | |
parser.add_argument('-c', '--config', required=True, action='store', metavar='FILENAME', help="Specify config file to use. * Required") | |
parser.add_argument('-r', '--read', action='store_true', help="Read temperatures from sensors. If --update is not specified rrd will not be updated and values will be printed to stdout") | |
parser.add_argument('-u', '--update', action='store_true', help='Update rrd with values from sensors, implies --read.') | |
parser.add_argument('-g', '--graph', action='store_true', help='Generate graphs from rrd values. If --update is specified then graphs are generated *after* sensors are read') | |
if len(sys.argv) == 1: | |
parser.print_help() | |
return | |
args = parser.parse_args() | |
LOCATIONS['config'] = args.config | |
read_config() | |
if args.update: | |
args.read = True | |
if args.read: | |
read_temps() | |
if not (args.update or args.graph): | |
for k, v in SENSORS.items(): | |
print '%s:%s:%.3f' % (v['ds'], k, v['value'] ) | |
if args.update: | |
update_rrd() | |
if args.graph: | |
graph_temps() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment