Skip to main content
 首页 » 编程设计

Python (PyRRD) 和带有 while 循环的 RRD

2025年05月04日10lautakyan007

已解决,进一步向下添加解决方案 我一直在尝试使用 PyRRD 从连接到我的 Raspberry Pi 的热传感器的输出创建一个图表,但没有运气让实际数据显示在图表中(但创建了 png 文件)。我不确定这是否是正确的方法,但这段代码每秒都会吐出温度,所以 while 循环至少可以工作。

import os 
import glob 
import time 
import subprocess 
 
# RDD-imports 
from pyrrd.graph import DEF, CDEF, VDEF 
from pyrrd.graph import LINE, AREA, GPRINT 
from pyrrd.graph import ColorAttributes, Graph 
from pyrrd.rrd import DataSource, RRA, RRD 
 
# Sensor-stuff  
os.system('modprobe w1-gpio') 
os.system('modprobe w1-therm') 
 
base_dir = '/sys/bus/w1/devices/' 
device_folder = glob.glob(base_dir + '28*')[0] 
device_file = device_folder + '/w1_slave' 
 
# RRD-stuff 
startTime = int(time.time()) 
filename = 'temptest.rrd' 
dataSources = [] 
rras = [] 
dataSource = DataSource(dsName='temp', dsType='DERIVE', heartbeat=5) 
dataSources.append(dataSource) 
rra1 = RRA(cf='AVERAGE', xff=0.5, steps=1, rows=5) 
rra2 = RRA(cf='AVERAGE', xff=0.5, steps=6, rows=10) 
rras.extend([rra1, rra2]) 
myRRD = RRD(filename, ds=dataSources, rra=rras, start=startTime) 
myRRD.create() 
 
# Graph-making 
graphfile = 'tempgraf.png' 
def1 = DEF(rrdfile=myRRD.filename, vname='mytemp', dsName=dataSource.name) 
# Data going into green field 
cdef1 = CDEF(vname='temp', rpn='%s,3600,*' % def1.vname) 
# Line for max value 
line1 = LINE(value=30, color='#990000', legend='Max temp allowed') 
# Green area 
area1 = AREA(defObj=cdef1, color='#006600', legend='Temp') 
 
def read_temp_raw(): 
    catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
    out,err = catdata.communicate() 
    out_decode = out.decode('utf-8') 
    lines = out_decode.split('\n') 
    return lines 
 
def read_temp(): 
    lines = read_temp_raw() 
    while lines[0].strip()[-3:] != 'YES': 
        time.sleep(0.2) 
        lines = read_temp_raw() 
    equals_pos = lines[1].find('t=') 
    if equals_pos != -1: 
        temp_string = lines[1][equals_pos+2:] 
        temp_c = float(temp_string) / 1000.0 
        myRRD.bufferValue(int(time.time()), int(temp_c)) 
        myRRD.update() 
        return temp_c 
 
while True: 
    print(read_temp()) 
    g = Graph(graphfile, start=startTime, end=int(time.time()), vertical_label='Temp(c)') 
    g.data.extend([def1, cdef1, line1, area1]) 
    g.write() 
    time.sleep(1) 

我一直在试验,阅读了很多 RRD 手册和初学者教程,但我就是做不好。我非常不确定#Graph-making 部分中的 rpn-stuff。请帮我 :) 另外,如果有更好的方法,请告诉我!

解决方案(针对我的问题):放弃 PyRRD 并试用 rrdtools 自己的 python 实现。 http://oss.oetiker.ch/rrdtool/prog/rrdpython.en.html

我在程序之外创建了数据库,并在终端 (Linux) 中正确设置了步骤:

rrdtool create dailyTemp.rrd --step 5      \ 
DS:temp:GAUGE:10:-100:200                  \ 
RRA:AVERAGE:0.5:1:2880 RRA:MAX:0.9:1:2880  \ 

然后我删除了所有连接到 PyRRD 的代码,并添加了一些导入行和一行用于 rrdtool 更新。更干净,现在我可以创建我的图表了:D 这是“最终”代码:

import os 
import glob 
import time 
import subprocess 
import sys 
sys.path.append('/usr/local/lib/python2.7/site-packages/') 
import rrdtool, tempfile 
 
# Sensor-stuff  
os.system('modprobe w1-gpio') 
os.system('modprobe w1-therm') 
 
base_dir = '/sys/bus/w1/devices/' 
device_folder = glob.glob(base_dir + '28*')[0] 
device_file = device_folder + '/w1_slave' 
 
# RRD-stuff, not specific 
startTime = int(time.time()) 
 
def read_temp_raw(): 
    catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
    out,err = catdata.communicate() 
    out_decode = out.decode('utf-8') 
    lines = out_decode.split('\n') 
    return lines 
 
def read_temp(): 
    lines = read_temp_raw() 
    while lines[0].strip()[-3:] != 'YES': 
        time.sleep(0.2) 
        lines = read_temp_raw() 
    equals_pos = lines[1].find('t=') 
    if equals_pos != -1: 
        temp_string = lines[1][equals_pos+2:] 
        temp_c = float(temp_string) / 1000.0 
        print(int(temp_c)) 
        print(int(time.time())) 
        rrdtool.update('dailyTemp.rrd','N:' + `temp_c`) 
        return temp_c 
 
while True: 
    print(read_temp()) 
    time.sleep(5) 

我还没有将图表创建到代码中,但可以打印出过去 2 小时的读数:

rrdtool graph temp120.png --end now --start end-7200s --width 400   \ 
    DEF:ds0a=dailyTemp.rrd:temp:AVERAGE             \ 

图表结果(进行中):获得所需声誉后立即添加图片 (10)

请您参考如下方法:

这是获取温度值然后更新 RRD 的另一种方法......

#!/usr/bin/python 
 
# reads 1-wire DS18B20 temperature sensors and outputs options for rrdupdate 
 
import os 
import glob 
import rrdtool 
 
sensors = ( {'aab8': {                 # last four characters of sensor ID 
                      'DS': 'DSName1', # DS name in rrd 
                      'value': 0 
                     }, 
             '5cc3': { 
                      'DS': 'DSName2', 
                      'value': 0 
                     }, 
             '9ce0': { 
                      'DS': 'DSName3', 
                      'value': 0 
                     } 
          } ) 
 
RRD='/path/to/my.rrd' 
 
base_dir = '/sys/bus/w1/devices/' 
device_folder = glob.glob(base_dir + '28*') 
 
DS_list = "" 
value_list = "N:" 
 
for index, sensor in enumerate(device_folder): 
    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 
                DS_list += v['DS'] + ':' 
                value_list += str(v['value']) + ':' 
 
DS_list = DS_list[:-1] 
value_list = value_list[:-1] 
 
rrdtool.update(RRD, '--template', DS_list, value_list)