def dev_write(self, *args): try: self.dev_sleep() return TCPModbusClient.dev_write(self.serverloc[0], self.serverloc[1], self.modbus_addr, *args) except: return None
def read_scale(self, modbus_addr): """Read the scale register on a dent""" self.modbus_addr = modbus_addr response = self.dev_read(self.scale_register, 3) data = [(TCPModbusClient.get_val(response.modbus_reg_val, i) & 0xffff) for i in range(0, response.modbus_val_bytes / 2)] if len(data) != 3: return None # return the scaling indicator expressed by the dent return data[1]
class VerisMeter: all_meters = range(1, 43) register_map = { 'current_scale': (1000, 1041), 'power_scale': (1042, 1083), 'energy_scale': (1084, 1125), 'kwh': (1168, 1251), 'kwh_fl': (2000, 2083), 'kw': (1252, 1293), 'pf': (1294, 1335), 'current': (1336, 1377), 'pkw': (1378, 1419), 'maxkw': (1420, 1461), 'pcurrent': (1462, 1503), 'maxcurrent': (1504, 1545), 'reset': (1126, 1167), } val_clear_kw = 10203 val_clear_max = 29877 def __init__(self, server, port, bus_addr): self.server = server self.port = port self.bus_addr = bus_addr self.logger = logging.getLogger('VerisMeter') self.last_reading_time = 0.0 self.last_reset_energy = None self.last_reset_time = 0.0 self.boot_time = time.time() def get_current(self): values = self.read_reg_range(self.register_map['current']) scales = self.read_reg_range(self.register_map['current_scale']) return self.scale_vals(values, scales) def get_power(self): values = self.read_reg_range(self.register_map['kw']) scales = self.read_reg_range(self.register_map['power_scale']) return self.scale_vals(values, scales) def get_powerfactor(self): values = self.read_reg_range(self.register_map['pf']) scales = [-3] * len(values) return self.scale_vals(values, scales) def get_energy_totals(self): values_16bit = self.read_reg_range(self.register_map['kwh']) scale = self.read_reg_range(self.register_map['energy_scale']) values = [] for i in range(0, len(values_16bit) / 2): values.append(((values_16bit[i * 2] & 0xffff) << 16) | (values_16bit[i * 2 + 1] & 0xffff)) return self.scale_vals(values, scale) def get_energy(self, current=None): if not current: current = self.get_energy_totals() if not self.last_reset_energy: return current return map(lambda x, y: x - y, current, self.last_reset_energy) def reset_energy(self, vals=None): # reset doesn't seem to work reliably -- just remember what it was last time if not vals: newvals = self.get_energy_totals() else: newvals = vals self.last_reset_time = time.time() self.last_reset_energy = newvals def scale_vals(self, vals, scale): return map(lambda x, y: x * (10**y), vals, scale) def read_reg_range(self, (start, end)): start -= 1 end -= 1 if end < start: self.logger.error("read_reg_range: invalid range: (%i, %i)" % (start, end)) return None self.logger.debug("read_reg_range: %i:%i" % (start, end)) now = time.time() if now - self.last_reading_time < 2: time.sleep(2 - (now - self.last_reading_time)) response = TCPModbusClient.dev_read(self.server, self.port, self.bus_addr, start, end - start + 1) self.last_reading_time = time.time() self.logger.debug("read_reg_range: %i response bytes", response.modbus_val_bytes) return [ TCPModbusClient.get_val(response.modbus_reg_val, i) for i in range(0, response.modbus_val_bytes / 2) ]
def update(self, elt, scale, modbus_addr): self.modbus_addr = modbus_addr response = self.dev_read(4000, 70) time.sleep(2) data = [(TCPModbusClient.get_val(response.modbus_reg_val, i) & 0xffff) for i in range(0, response.modbus_val_bytes / 2)] if len(data) != 70: print "Short read from", self.serverloc, modbus_addr return reading_time = int(time.time()) base = '/%s' % elt self.add(base + '/ABC/true_energy', reading_time, float(self.to_word(data[0:2])) / e_d(scale)) self.add(base + '/ABC/reactive_energy', reading_time, float(self.to_word(data[7:9])) / e_d(scale)) self.add(base + '/ABC/apparent_energy', reading_time, float(self.to_word(data[10:12])) / e_d(scale)) self.add(base + '/ABC/true_power', reading_time, float(data[2]) / e_d(scale)) # min=data[6], max=data[5])) self.add(base + '/ABC/reactive_power', reading_time, float(data[9]) / e_d(scale)) self.add(base + '/ABC/apparent_power', reading_time, float(data[12]) / e_d(scale)) self.add(base + '/ABC/displacement_pf', reading_time, float(data[13]) / 100) self.add(base + '/ABC/apparent_pf', reading_time, float(data[14]) / 100) self.add(base + '/ABC/current', reading_time, float(data[15]) / c_d(scale)) # line frequency divisor is not in the datasheet, but called Dent to verify 3-26-2010 self.add(base + '/ABC/line_frequency', reading_time, float(data[21]) / 100) self.add(base + '/AB/volts', reading_time, float(data[18]) / v_d(scale)) self.add(base + '/BC/volts', reading_time, float(data[19]) / v_d(scale)) self.add(base + '/AC/volts', reading_time, float(data[20]) / v_d(scale)) def w_i(d, i): return d[i] | (d[i+1] << 16) for (i,v) in [(0,'A'), (1,'B'), (2,'C')]: base = '/%s/%s/' % (elt, v) self.add(base + 'true_energy', reading_time, float(w_i(data, 22+(i*2))) / e_d(scale)) self.add(base + 'reactive_energy', reading_time, float(w_i(data, 31+(i*2))) / e_d(scale)) self.add(base + 'apparent_energy', reading_time, float(w_i(data, 40+(i*2))) / e_d(scale)) self.add(base + 'true_power', reading_time, float(data[28+i]) / e_d(scale)) self.add(base + 'reactive_power', reading_time, float(data[37+i]) / e_d(scale)) self.add(base + 'apparent_power', reading_time, float(data[46+i]) / e_d(scale)) self.add(base + 'displacement_pf', reading_time, float(data[49+i]) / 100) self.add(base + 'apparent_pf', reading_time, float(data[52+i]) / 100) self.add(base + 'current', reading_time, float(data[55+i]) / c_d(scale)) self.add(base + 'phase-neutral_voltage', reading_time, float(data[58+i]) / v_d(scale))
def dev_write(self, *args): try: self.dev_sleep() return TCPModbusClient.dev_write(self.serverloc[0], self.serverloc[1],self.modbus_addr,*args) except: return None
def update(self, elt, scale, modbus_addr): self.modbus_addr = modbus_addr response = self.dev_read(4000, 70) time.sleep(2) data = [(TCPModbusClient.get_val(response.modbus_reg_val, i) & 0xffff) for i in range(0, response.modbus_val_bytes / 2)] if len(data) != 70: print "Short read from", self.serverloc, modbus_addr return reading_time = int(time.time()) base = '/%s' % elt self.add(base + '/ABC/true_energy', reading_time, float(self.to_word(data[0:2])) / e_d(scale)) self.add(base + '/ABC/reactive_energy', reading_time, float(self.to_word(data[7:9])) / e_d(scale)) self.add(base + '/ABC/apparent_energy', reading_time, float(self.to_word(data[10:12])) / e_d(scale)) self.add(base + '/ABC/true_power', reading_time, float(data[2]) / e_d(scale)) # min=data[6], max=data[5])) self.add(base + '/ABC/reactive_power', reading_time, float(data[9]) / e_d(scale)) self.add(base + '/ABC/apparent_power', reading_time, float(data[12]) / e_d(scale)) self.add(base + '/ABC/displacement_pf', reading_time, float(data[13]) / 100) self.add(base + '/ABC/apparent_pf', reading_time, float(data[14]) / 100) self.add(base + '/ABC/current', reading_time, float(data[15]) / c_d(scale)) # line frequency divisor is not in the datasheet, but called Dent to verify 3-26-2010 self.add(base + '/ABC/line_frequency', reading_time, float(data[21]) / 100) self.add(base + '/AB/volts', reading_time, float(data[18]) / v_d(scale)) self.add(base + '/BC/volts', reading_time, float(data[19]) / v_d(scale)) self.add(base + '/AC/volts', reading_time, float(data[20]) / v_d(scale)) def w_i(d, i): return d[i] | (d[i + 1] << 16) for (i, v) in [(0, 'A'), (1, 'B'), (2, 'C')]: base = '/%s/%s/' % (elt, v) self.add(base + 'true_energy', reading_time, float(w_i(data, 22 + (i * 2))) / e_d(scale)) self.add(base + 'reactive_energy', reading_time, float(w_i(data, 31 + (i * 2))) / e_d(scale)) self.add(base + 'apparent_energy', reading_time, float(w_i(data, 40 + (i * 2))) / e_d(scale)) self.add(base + 'true_power', reading_time, float(data[28 + i]) / e_d(scale)) self.add(base + 'reactive_power', reading_time, float(data[37 + i]) / e_d(scale)) self.add(base + 'apparent_power', reading_time, float(data[46 + i]) / e_d(scale)) self.add(base + 'displacement_pf', reading_time, float(data[49 + i]) / 100) self.add(base + 'apparent_pf', reading_time, float(data[52 + i]) / 100) self.add(base + 'current', reading_time, float(data[55 + i]) / c_d(scale)) self.add(base + 'phase-neutral_voltage', reading_time, float(data[58 + i]) / v_d(scale))