""" Module to Store Sensor Data into an RRD Database and update Corresponding Graphs """ import _thread, time import rrdtool class RRDDB(object): """ Class to Represent the RRD Data of a Single Multi-Value Sensor """ def __init__(self, rrdfile, sid, imgpath=None, sensor_type="thp"): """ Initialize Class Arguments: rrdfile: Path to the RRD Database File (mandatory) sid: Sensor ID which this RRD Database is for (mandatory) imgpath: Path to Store Images, if set Images will be updated on call of notify() sensor_type: Any combination of the following Letters: t - Temperature h - Humidity p - Pressure Default is 'thp' for a sensor sending all 3 values """ self.__rrdfile = rrdfile self.__sid = sid self.__imgpath = imgpath self.__t = bool('t' in sensor_type) self.__h = bool('h' in sensor_type) self.__p = bool('p' in sensor_type) def create(self, interval): """ Create a new RRD Database According to the Specified Sensor Types Arguments: interval: Seconds between Sensor Updates """ datasrc = [] datasrc.append('DS:v:GAUGE:' + str(interval*2) + ':U:U') datasrc.append('DS:r:GAUGE:' + str(interval*2) + ':U:U') if self.__t: datasrc.append('DS:t:GAUGE:' + str(interval*2) + ':U:U') if self.__h: datasrc.append('DS:h:GAUGE:' + str(interval*2) + ':U:U') if self.__p: datasrc.append('DS:p:GAUGE:' + str(interval*2) + ':U:U') rrdtool.create(self.__rrdfile, '--step', str(interval), datasrc, 'RRA:LAST:0.5:1:105120', 'RRA:AVERAGE:0.5:6:175680', 'RRA:MAX:0.5:6:175680', 'RRA:MIN:0.5:6:175680') def notify(self, msg): """ Notify Method Called from the Receiver Class, Inserts Values into the RRD Database Arguments: msg: Object Representation of the Sensor Data """ if msg['sid'] == self.__sid: updstr = 'N:' + str(msg['v']) + ':' + str(msg['rssi']) if self.__t: updstr = updstr + ':' + str(msg['t']) if self.__h: updstr = updstr + ':' + str(msg['h']) if self.__p: updstr = updstr + ':' + str(msg['p']) rrdtool.update(self.__rrdfile, updstr) if self.__imgpath != None: _thread.start_new_thread(self.update_web, ()) def _graph(self, value, start): """ Draw a Graph for a Specified Sensor Value Arguments: value: Sensor Identifier (t, h, p, v or r) start: When to Start the Graph (24h, 7d, 30d, 1y) """ types = {'t': ['Temperatur', '#FF0000', '°C'], 'h': ['Luftfeuchte', '#0000FF', '%%'], 'p': ['Luftdruck', '#00FF00', 'hPa'], 'v': ['Batterie', '#FFFF00', 'V'], 'r': ['RSSI', '#00FFFF', '']} times = {'24h': ['Letzte 24h', 'LAST'], '7d': ['Letzte 7 Tage', 'AVERAGE'], '30d': ['Letzte 30 Tage', 'AVERAGE'], '1y': ['Letzte 12 Monate', 'AVERAGE']} rrdtool.graph(self.__imgpath + '/graph_' + value + '_' + start + '.png', '-s', 'now-' + start, '-e', 'now', '-t', times[start][0], '-z', '-A', 'DEF:val=' + self.__rrdfile + ':'+ value + ':' + times[start][1], 'VDEF:valmax=val,MAXIMUM', 'VDEF:valmin=val,MINIMUM', 'VDEF:valavg=val,AVERAGE', 'LINE2:val'+types[value][1]+':'+types[value][0], 'GPRINT:valavg:Avg %2.2lf '+types[value][2], 'GPRINT:valmin:Min %2.2lf '+types[value][2], 'GPRINT:valmax:Max %2.2lf '+types[value][2]) def update_web(self): """ Renew RRD Graphs and HTML for the Sensor Values """ if self.__t: self._graph('t', '24h') self._graph('t', '7d') self._graph('t', '30d') self._graph('t', '1y') if self.__h: self._graph('h', '24h') self._graph('h', '7d') self._graph('h', '30d') self._graph('h', '1y') if self.__p: self._graph('p', '24h') self._graph('p', '7d') self._graph('p', '30d') self._graph('p', '1y') last = rrdtool.lastupdate(self.__rrdfile) with open(self.__imgpath + '/index.html', 'w') as html: html.write('\n\n') html.write('\n') html.write('') html.write('Sensorlog RBS 3.OG\n') html.write('\n\n
') if self.__t: html.write('

Temperatur

') html.write('

Aktuell ' + str(last['ds']['t']) + ' °C

') html.write('Daily Graph') html.write('Weekly Graph') html.write('Monthly Graph') html.write('Yearly Graph
\n') if self.__h: html.write('

Luftfeuchte

') html.write('

Aktuell ' + str(last['ds']['h']) + ' %

') html.write('Daily Graph') html.write('Weekly Graph') html.write('Monthly Graph') html.write('Yearly Graph
\n') if self.__p: html.write('

Luftdruck

') html.write('

Aktuell ' + str(last['ds']['p']) + ' hPa

') html.write('Daily Graph') html.write('Weekly Graph') html.write('Monthly Graph') html.write('Yearly Graph
\n') if float(last['ds']['v']) < 2.5: html.write('

Batterien sind fast leer, bitte Wechseln!

') html.write('

Letztes Update: '+time.strftime('%d.%m.%Y %H:%M:%S')+' | Batteriespannung: '+str(last['ds']['v'])+'V

') html.write('
')