Read power ports' status

This commit is contained in:
Yeongdo Park 2020-02-17 12:40:35 -08:00
parent 164a768d13
commit 16ca41bd5d

View file

@ -2,11 +2,175 @@ import easymodbus.modbusClient
from datetime import datetime as dt
from functools import reduce
nRegsPortStatus = 32
addrControlAC1 = 64
addrStatusAC1 = 96
addrControlDC2 = 128
addrStatusDC2 = 160
addrControlDC3 = 192
addrStatusDC3 = 224
addrControlSystem = 0x0100
addrStatusSystem = 0x0120
addrStatusThermal = 0x0160
addrStatusDiagnostic = 0x0180
p1_port_status = {0: "AC1 port is real power soft-limiting",
1: "AC1 port is current soft-limiting",
2: "AC1 port is reactive power soft-limiting",
3: "AC1 port is power derated (limited) due to high temperature",
4: "Reserved",
5: "AC1 port is throttling back on port DC2 due to soft-limiting",
6: "Reserved",
7: "AC1 port is throttling back on port DC3 due to soft-limiting",
8: "AC1 port has the seamless transfer feature enabled when in FPWR control",
9: "The PCS SEL-547 interface transfer switch HW is indicating the PCS is islanded (islanding contactor is commanded to open). If enabled, the PCS is able to form a microgrid in FPWR control.",
10: "The PCS SEL-547 interface transfer switch HW is indicating the PCS is islanded (islanding contactor has successfully opened). If enabled, the PCS is able to form a microgrid in FPWR control.",
11: "Reserved",
12: "Reserved",
13: "Reserved",
14: "Reserved",
15: "Reserved"}
p2_port_status = {0: "DC2 port is power soft-limiting",
1: "DC2 port is current soft-limiting",
2: "Reserved",
3: "DC2 port is power derated (limited) due to high temperature",
4: "Reserved",
5: "DC2 port is throttling back on port AC1 due to soft-limiting",
6: "Reserved",
7: "DC2 port is throttling back on port DC3 due to soft-limiting",
8: "Reserved",
9: "Reserved",
10: "Reserved",
11: "Reserved",
12: "Reserved",
13: "Reserved",
14: "Reserved",
15: "Reserved"}
p3_port_status = {0: "DC3 port is power soft-limiting",
1: "DC3 port is current soft-limiting",
2: "Reserved",
3: "DC3 port is power derated (limited) due to high temperature",
4: "Reserved",
5: "DC3 port is throttling back on port AC1 due to soft-limiting",
6: "Reserved",
7: "DC3 port is throttling back on port DC2 due to soft-limiting",
8: "Reserved",
9: "Reserved",
10: "Reserved",
11: "Reserved",
12: "Reserved",
13: "Reserved",
14: "Reserved",
15: "Reserved"}
def toPower(x):
return x * 10
def toVar(x):
return x * 10
def toVa(x):
return x * 10
def toPwrFactor(x):
return x * 0.01
def toCurrent(x):
return x * 0.1
def toVoltage(x):
return x
def toFreq(x):
return x * 0.001
def toTemperature(x):
return x * 0.1
def toRpm(x):
return x
def toMinutes(x):
return x
def toTime(x):
return x // 60, x % 60
def toBaud(x):
return x * 100
def toString(r):
ms = r >> 8
ls = (r & 0xff)
return chr(ms) + chr(ls)
def toBitString(r):
return bin(r)[2:].zfill(16)
def selectMessages (bits, msgDict):
msgs = []
for i, bit in enumerate(bits[::-1]):
if bit == '1':
msgs.append(msgDict[i])
return msgs
def parse_address (addr_string):
import re
m = re.findall(r'0x([0-9A-F]+)', addr_string)
if len(m) > 1:
start, end = m
elif len(m) > 0:
start = m[0]
end = start
else:
raise ValueError()
nregisters = int(end, 16) - int(start, 16) + 1
return int(start, 16), nregisters
class StabilitiRegister(object):
def __init__(self, name, proplist):
self.name = name
self.index = proplist[0]
self.address, self.size = parse_address(proplist[1])
self.access = proplist[2]
self.dtype = proplist[3]
self.vrange = proplist[4]
self.vdefault = proplist[5]
def isreadonly(self):
return self.is_readable() and (not self.is_writable())
def is_readable(self):
return 'R' in self.access
def is_writable(self):
return 'W' in self.access
def getdefaultvalue(self):
if self.vdefault = 'NA':
return None
else:
return self.vdefault
class StabilitiController(object):
''''''
def __init__(self, ipaddr, port=502, uid=240):
self.client = easymodbus.modbusClient.ModbusClient(ipaddr, port)
self.client.unitidentifier = uid
self.reg_info = {}
def checkConnect(self):
if not self.client.is_connected():
@ -17,9 +181,7 @@ class StabilitiController(object):
self.client.close()
def reg2str(self, r):
ms = (r & 0xff00) >> 8
ls = (r & 0xff)
return chr(ms) + chr(ls)
return toString(r)
def getNetworkConfigs(self, config=None):
self.checkConnect()
@ -128,5 +290,104 @@ b3-b4: The status of the fault.
pass
def getSystemStatus(self):
'''Get PCS Status'''
'''\
system_status[0] PCS in self-test mode
system_status[1] PCS reconnect timer 0 counting down from last disconnect due to ABORT-0 fault
system_status[2] PCS reconnect timer 1 counting down from last disconnect due to ABORT-1 fault
system_status[3] PCS reconnect timer 2 counting down from last disconnect due to ABORT-2 fault
system_status[4] PCS DC2 port pre-charge operation is active
system_status[5] Invalid control method programmed in PCS
system_status[6] AC rotation indication ( 0 AC1 port wired as A-B-C | 1 AC1 port wired as C-B-A )
system_status[7] PV/MPPT low-voltage indication ( 0 PV/MPPT is disabled due to low voltage at port | 1 PV/MPPT is enabled with voltage above minimum PV/MPPT limit set for port )
system_status[8] PV/MPPT time-of-day indication ( 0 System time-of-day outside PV/MPPT operational range | 1 System time-of-day satisfies start-time and stop-time limits set for PV/MPPT port, PV/MPPT port allowed to convert power )
system_status[9] PCS power conversion is active
system_status[10] PCS hardware shutdown function is active (power conversion disabled)
system_status[11] PCS lockdown active due to GFDI fault, IMI fault, or fan fault
system_status[12] PCS fault of severity level ABORT-0 active
system_status[13] PCS fault of severity level ABORT-1 active
system_status[14] PCS fault of severity level ABORT-2 active
system_status[15] PCS GFDI fault or IMI fault detected
'''
regs = self.client.read_holdingregisters(addrStatusSystem, nRegsPortStatus)
pass
def getPortStatusAC1(self):
'''Get Status of AC1 Power Port'''
def relAddr(x):
return x - addrStatusAC1
regs = self.client.read_holdingregisters(addrStatusAC1, nRegsPortStatus)
p1_all_status = {"p1_port_status": toBitString(regs[relAddr(96)]),
"p1_real_pwr_ramped": toPower(regs[relAddr(100)]),
"p1_reactive_pwr_ramped": toVar(regs[relAddr(101)]),
"p1_frequency": toFreq(regs[relAddr(105)]),
"p1_v_ab_rms": toVoltage(regs[relAddr(109)]),
"p1_v_bc_rms": toVoltage(regs[relAddr(110)]),
"p1_v_ca_rms": toVoltage(regs[relAddr(111)]),
"p1_v_an_rms": toVoltage(regs[relAddr(112)]),
"p1_v_bn_rms": toVoltage(regs[relAddr(113)]),
"p1_v_cn_rms": toVoltage(regs[relAddr(114)]),
"p1_power_factor": toPwrFactor(regs[relAddr(118)]),
"p1_real_power": toPower(regs[relAddr(119)]),
"p1_reactive_power": toVar(regs[relAddr(120)]),
"p1_apparent_power": toVa(regs[relAddr(121)]),
"p1_i_a_int_rms": toCurrent(regs[relAddr(122)]),
"p1_i_b_int_rms": toCurrent(regs[relAddr(123)]),
"p1_i_c_int_rms": toCurrent(regs[relAddr(124)]),
"p1_i_a_ext_rms": toCurrent(regs[relAddr(125)]),
"p1_i_b_ext_rms": toCurrent(regs[relAddr(126)]),
"p1_i_c_ext_rms": toCurrent(regs[relAddr(127)])}
status = p1_all_status['p1_port_status']
return selectMessages(status, p1_port_status), p1_all_status
def getPortStatusDC2(self):
'''Get Status of DC2 Power Port'''
def relAddr(x):
return x - addrStatusDC2
regs = self.client.read_holdingregisters(addrStatusDC2, nRegsPortStatus)
p2_all_status = {'p2_port_status': toBitString(regs[relAddr(160)]),
'p2_current_ramped': toCurrent(regs[relAddr(164)]),
'p2_power_ramped': toPower(regs[relAddr(165)]),
'p2_voltage_ramped': toVoltage(regs[relAddr(166)]),
'pv_tod_stat': toMinutes(regs[relAddr(167)]),
'p2_pv_restart_stat': regs[relAddr(168)],
'p2_v_pn': toVoltage(regs[relAddr(173)]),
'p2_v_pg': toVoltage(regs[relAddr(176)]),
'dc_com_voltage': toVoltage(regs[relAddr(177)]),
'p2_power': toPower(regs[relAddr(185)]),
'p2_current': toCurrent(regs[relAddr(186)])}
status = p2_all_status['p2_port_status']
return selectMessages(status, p2_port_status), p2_all_status
def getPortStatusDC3(self):
'''Get Status of DC3 Power Port'''
def relAddr(x):
return x - addrStatusDC3
regs = self.client.read_holdingregisters(addrStatusDC3, nRegsPortStatus)
p3_all_status = {'p3_port_status': toBitString(regs[relAddr(224)]),
'p3_current_ramped': toCurrent(regs[relAddr(228)]),
'p3_power_ramped': toPower(regs[relAddr(229)]),
'p3_voltage_ramped': toVoltage(regs[relAddr(230)]),
'p3_pv_restart_stat': regs[relAddr(232)],
'p3_v_pn': toVoltage(regs[relAddr(237)]),
'p3_v_pg': toVoltage(regs[relAddr(240)]),
'p3_power': toPower(regs[relAddr(249)]),
'p3_current': toCurrent(regs[relAddr(250)])}
status = p3_all_status['p3_port_status']
return selectMessages(status, p3_port_status), p3_all_status