Skip to content

Instantly share code, notes, and snippets.

@tdack
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tdack/9129944 to your computer and use it in GitHub Desktop.
Save tdack/9129944 to your computer and use it in GitHub Desktop.
DS18B20 1-wire data collection on Raspberry Pi
#!/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()
#!/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()
[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
#!/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