All register view and operation control working.

This commit is contained in:
Yeongdo Park 2020-02-19 14:30:17 -08:00
parent 17aebdf6d4
commit e2f3ad1ccd
5 changed files with 889 additions and 177 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
/venv/
*.bak
/__pycache__/
/#~wxg.autosave~faultView.wxg#

View file

@ -6,12 +6,17 @@
import wx
import wx.grid
import wx.propgrid
import gettext
gettext.install(None)
from pubsub import pub
import re
from registers import regdict
print('pubsub API version', pub.VERSION_API)
from pubsub.utils.notification import useNotifyByWriteFile
@ -31,6 +36,7 @@ class Controller:
self.view = view
self.timer = wx.Timer()
self.timer.Bind(wx.EVT_TIMER, self.OnTimer)
self.refresh_rate = 2000
self.mode = False
pub.subscribe(self.getFaultInfo, 'fault_selected')
@ -40,9 +46,19 @@ class Controller:
pub.subscribe(self.resetNetworkConfigs, 'reset_network_configs')
pub.subscribe(self.resetPcsRemote, 'reset_pcs_remote')
pub.subscribe(self.checkSysOpMode, 'check_system_op_mode')
pub.subscribe(self.startSystemOp, "start_system_op_manual")
pub.subscribe(self.stopSystemOp, "stop_system_op_manual")
def startSystemOp(self, mode, val):
self.sc.setPortModes(mode)
self.sc.setPortSetpoints(val)
self.sc.setUserStart()
def stopSystemOp(self):
self.sc.setUserStop()
def startTimer(self):
self.timer.Start(2000)
self.timer.Start(self.refresh_rate)
def stopTimer(self):
self.timer.Stop()
@ -50,6 +66,7 @@ class Controller:
def applyNetworkConfigs(self, ncDict):
if self.sc:
self.sc.checkClose()
self.refresh_rate = ncDict.pop("refresh")
self.sc = SC(**ncDict)
def resetNetworkConfigs(self):
@ -84,14 +101,73 @@ class Controller:
self.view.text_fault_status.SetValue(status_text)
def OnTimer(self, event):
# Read registers
self.sc.readAllRegisters()
# Process registers
# Show Registers
factivity = self.sc.readFaultActivity()
foccurence = self.sc.readFaultOccurence()
self.view.SetFaultGrid(factivity, foccurence)
event.Skip()
stats = list(range(4))
stats[0], _ = (self.sc.getSystemStatus())
stats[1], _ = (self.sc.getPortStatusAC1())
stats[2], _ = (self.sc.getPortStatusDC2())
stats[3], _ = (self.sc.getPortStatusDC3())
self.view.update_status(list(map("\n".join, stats)))
'''
for item in self.writeQueue:
name, value = item
self.sc.write(name, value)
'''
class MyFrame(FaultFrame):
def __init__(self, *args, **kwds):
FaultFrame.__init__(self, *args, **kwds)
self.property_page = self.property_grid_1.AddPage("Ports")
self.property_page_etc = self.property_grid_1.AddPage("Etc")
for k in regdict:
prop = wx.propgrid.StringProperty(label=k, value="")
prop.SetHelpString(str(regdict[k]))
if re.search(r'^p[1-3]_', k):
self.property_page.Append(prop)
else:
self.property_page_etc.Append(prop)
self.property_page.Sort()
self.property_page_etc.Sort()
# self.property_page.SetPropertyAttributeAll("Raw", 0)
# self.property_page_etc.SetPropertyAttributeAll("Raw", 0)
self.property_grid_1.SetPropertyAttributeAll("Units", 0)
self.property_grid_1.SetColumnCount(3, self.property_page.GetIndex())
self.property_grid_1.SetColumnCount(3, self.property_page_etc.GetIndex())
self.property_grid_1.ShowHeader()
pub.subscribe(self.update_display, 'read_all_registers')
def update_status(self, stats):
self.text_ctrl_system_status.SetValue(stats[0])
self.text_ctrl_ac1_status.SetValue(stats[1])
self.text_ctrl_dc2_status.SetValue(stats[2])
self.text_ctrl_dc3_status.SetValue(stats[3])
def update_display(self, reg, info):
ports = {k:v for (k,v) in info.items() if re.search(r'^p[1-3]_', k)}
etc = {k:v for (k,v) in info.items() if not re.search(r'^p[1-3]_', k)}
for k, v in ports.items():
self.property_page.SetPropertyValue(k, str(v.convertValue(reg[v.address])))
self.property_page.SetPropertyAttribute(k, "Units", str((reg[v.address])))
for k, v in etc.items():
self.property_page_etc.SetPropertyValue(k, str(v.convertValue(reg[v.address])))
self.property_page_etc.SetPropertyAttribute(k, "Units", str((reg[v.address])))
def OnFaultSelect(self, event): # wxGlade: MyFrame.<event_handler>
pub.sendMessage("fault_selected", pos=(event.GetRow(), event.GetCol()))
@ -103,8 +179,12 @@ class MyFrame(FaultFrame):
for j in range(8):
if fActivity[i*8+j] == '1':
self.fault_grid.SetCellBackgroundColour(i, j, wx.LIGHT_GREY)
else:
self.fault_grid.SetCellBackgroundColour(i, j, wx.WHITE)
if fOccurence[i*8+j] == '1':
self.fault_grid.SetCellValue(i, j, "O")
else:
self.fault_grid.SetCellValue(i, j, "")
def ToggleMonitoring(self, event): # wxGlade: MyFrame.<event_handler>
btnLabel = self.button_1.GetLabel()
@ -115,9 +195,6 @@ class MyFrame(FaultFrame):
pub.sendMessage("monitoring_stopped")
self.button_1.SetLabel("Start")
if event:
event.Skip()
def OnApply(self, event):
if self.button_1.Enabled:
@ -132,6 +209,7 @@ class MyFrame(FaultFrame):
"ipaddr": self.input_ip.GetValue(),
"port": int(self.input_port.GetValue()),
"uid": int(self.input_uid.GetValue()),
"refresh": int(self.input_refresh.GetValue()),
}
pub.sendMessage("apply_network_configs", ncDict=ncDict)
@ -161,6 +239,25 @@ class MyFrame(FaultFrame):
def OnCheckSysOpMode(self, event):
pub.sendMessage("check_system_op_mode")
def OnOpStart(self, event):
mode = (self.choice_ac1_control.GetStringSelection(),
self.choice_dc2_control.GetStringSelection(),
self.choice_dc3_control.GetStringSelection())
inputs = {
"p1_real_pwr_setpt": self.text_ctrl_ac1_realpwr.Value,
"p1_react_pwr_setpt": self.text_ctrl_ac1_reactpwr.Value,
"p2_current_setpt": self.text_ctrl_dc2_current.Value,
"p2_power_setpt": self.text_ctrl_dc2_power.Value,
"p2_voltage_setpt": self.text_ctrl_dc2_voltage.Value,
"p3_current_setpt": self.text_ctrl_dc3_current.Value,
"p3_power_setpt": self.text_ctrl_dc3_power.Value,
"p3_voltage_setpt": self.text_ctrl_dc3_voltage.Value,
}
pub.sendMessage("start_system_op_manual", mode=mode, val=inputs)
def OnOpStop(self, event):
pub.sendMessage("stop_system_op_manual")
# end of class MyFrame
class MyApp(wx.App):

View file

@ -1,10 +1,11 @@
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.5 on Thu Feb 13 18:40:11 2020
# generated by wxGlade 0.9.5 on Tue Feb 18 18:22:15 2020
#
import wx
import wx.grid
import wx.propgrid
# begin wxGlade: dependencies
import gettext
@ -19,7 +20,7 @@ class FaultFrame(wx.Frame):
# begin wxGlade: FaultFrame.__init__
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((632, 556))
self.SetSize((1099, 729))
self.input_ip = wx.TextCtrl(self, wx.ID_ANY, _("192.168.1.21"))
self.input_port = wx.TextCtrl(self, wx.ID_ANY, _("502"))
self.input_uid = wx.TextCtrl(self, wx.ID_ANY, _("240"))
@ -27,13 +28,35 @@ class FaultFrame(wx.Frame):
self.reset_button = wx.Button(self, wx.ID_ANY, _("Reset Connection"))
self.apply_button = wx.Button(self, wx.ID_ANY, _("Apply"))
self.rreset_button = wx.Button(self, wx.ID_ANY, _("Remote PCS Reset"))
self.some_button = wx.Button(self, wx.ID_STOP, "")
self.button_1 = wx.ToggleButton(self, wx.ID_ANY, _("Start"))
self.op_mode_button = wx.Button(self, wx.ID_ANY, _("System OP Mode"))
self.text_op_mode = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
self.text_ctrl_system_status = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
self.text_ctrl_ac1_status = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
self.text_ctrl_dc2_status = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
self.text_ctrl_dc3_status = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
self.fault_grid = wx.grid.Grid(self, wx.ID_ANY, size=(1, 1))
self.button_1 = wx.ToggleButton(self, wx.ID_ANY, _("Start"))
self.text_fault_doc = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
self.text_fault_status = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
self.panel_1 = wx.Panel(self, wx.ID_ANY)
self.button_2 = wx.Button(self.panel_1, wx.ID_ANY, _("Start"))
self.button_3 = wx.Button(self.panel_1, wx.ID_ANY, _("Stop"))
self.choice_ac1_control = wx.Choice(self.panel_1, wx.ID_ANY, choices=[_("IDLE"), _("NET"), _("GPWR"), _("FPWR")])
self.text_ctrl_ac1_realpwr = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.text_ctrl_ac1_reactpwr = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.choice_dc2_control = wx.Choice(self.panel_1, wx.ID_ANY, choices=[_("IDLE"), _("NET"), _("PV/MPPT"), _("CURR"), _("PWR"), _("VOLT")])
self.text_ctrl_dc2_current = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.text_ctrl_dc2_power = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.text_ctrl_dc2_voltage = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.text_ctrl_7 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
self.text_ctrl_8 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
self.button_4 = wx.Button(self.panel_1, wx.ID_ANY, _("Enable Precharge"))
self.button_5 = wx.Button(self.panel_1, wx.ID_ANY, _("Disable Precharge"))
self.choice_dc3_control = wx.Choice(self.panel_1, wx.ID_ANY, choices=[_("IDLE"), _("NET"), _("PV/MPPT"), _("CURR"), _("PWR"), _("VOLT")])
self.text_ctrl_dc3_current = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.text_ctrl_dc3_power = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.text_ctrl_dc3_voltage = wx.TextCtrl(self.panel_1, wx.ID_ANY, _("0"))
self.property_grid_1 = wx.propgrid.PropertyGridManager(self, wx.ID_ANY, style=wx.propgrid.PG_DESCRIPTION | wx.propgrid.PG_TOOLBAR)
self.__set_properties()
self.__do_layout()
@ -41,14 +64,18 @@ class FaultFrame(wx.Frame):
self.Bind(wx.EVT_BUTTON, self.OnReset, self.reset_button)
self.Bind(wx.EVT_BUTTON, self.OnApply, self.apply_button)
self.Bind(wx.EVT_BUTTON, self.OnButtonRemoteReset, self.rreset_button)
self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleMonitoring, self.button_1)
self.Bind(wx.EVT_BUTTON, self.OnCheckSysOpMode, self.op_mode_button)
self.Bind(wx.grid.EVT_GRID_CMD_CELL_LEFT_CLICK, self.OnFaultSelect, self.fault_grid)
self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleMonitoring, self.button_1)
self.Bind(wx.EVT_BUTTON, self.OnOpStart, self.button_2)
self.Bind(wx.EVT_BUTTON, self.OnOpStop, self.button_3)
# end wxGlade
def __set_properties(self):
# begin wxGlade: FaultFrame.__set_properties
self.SetTitle(_("frame"))
self.SetTitle(_("PCS Controller"))
self.rreset_button.Enable(False)
self.button_1.Enable(False)
self.fault_grid.CreateGrid(8, 8)
self.fault_grid.SetRowLabelSize(30)
self.fault_grid.SetColLabelSize(30)
@ -73,16 +100,25 @@ class FaultFrame(wx.Frame):
self.fault_grid.SetRowSize(6, 30)
self.fault_grid.SetRowSize(7, 30)
self.fault_grid.SetMinSize((270, 270))
self.button_1.Enable(False)
self.text_fault_doc.SetMinSize((-1, 120))
self.text_fault_status.SetMinSize((-1, 120))
self.choice_ac1_control.SetSelection(0)
self.choice_dc2_control.SetSelection(0)
self.choice_dc3_control.SetSelection(0)
# end wxGlade
def __do_layout(self):
# begin wxGlade: FaultFrame.__do_layout
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2 = wx.BoxSizer(wx.VERTICAL)
sizer_11 = wx.StaticBoxSizer(wx.StaticBox(self.panel_1, wx.ID_ANY, _("DC3 Port")), wx.HORIZONTAL)
grid_sizer_2 = wx.GridSizer(4, 2, 0, 0)
sizer_10 = wx.StaticBoxSizer(wx.StaticBox(self.panel_1, wx.ID_ANY, _("DC2 Port")), wx.HORIZONTAL)
grid_sizer_1 = wx.GridSizer(7, 2, 0, 0)
sizer_9 = wx.StaticBoxSizer(wx.StaticBox(self.panel_1, wx.ID_ANY, _("AC1 Port")), wx.HORIZONTAL)
grid_sizer_3 = wx.GridSizer(3, 2, 0, 0)
sizer_5 = wx.StaticBoxSizer(wx.StaticBox(self.panel_1, wx.ID_ANY, _("Manual Mode Control")), wx.HORIZONTAL)
sizer_3 = wx.BoxSizer(wx.VERTICAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_7 = wx.BoxSizer(wx.VERTICAL)
sizer_8 = wx.BoxSizer(wx.VERTICAL)
sizer_4 = wx.GridSizer(7, 2, 0, 0)
label_1 = wx.StaticText(self, wx.ID_ANY, _("IP Address"))
sizer_4.Add(label_1, 0, 0, 0)
@ -99,16 +135,85 @@ class FaultFrame(wx.Frame):
sizer_4.Add(self.reset_button, 0, 0, 0)
sizer_4.Add(self.apply_button, 0, 0, 0)
sizer_4.Add(self.rreset_button, 0, 0, 0)
sizer_4.Add(self.some_button, 0, 0, 0)
sizer_4.Add(self.button_1, 0, 0, 0)
sizer_4.Add(self.op_mode_button, 0, 0, 0)
sizer_4.Add(self.text_op_mode, 0, 0, 0)
sizer_1.Add(sizer_4, 1, wx.EXPAND, 0)
sizer_2.Add(self.fault_grid, 0, wx.ALIGN_CENTER, 0)
sizer_2.Add(self.button_1, 0, wx.ALIGN_CENTER, 0)
sizer_3.Add(sizer_2, 1, wx.ALIGN_CENTER, 0)
sizer_3.Add(self.text_fault_doc, 0, wx.EXPAND, 0)
sizer_3.Add(self.text_fault_status, 0, wx.EXPAND, 0)
sizer_7.Add(sizer_4, 0, wx.EXPAND, 0)
label_21 = wx.StaticText(self, wx.ID_ANY, _("System Status"))
sizer_8.Add(label_21, 0, 0, 0)
sizer_8.Add(self.text_ctrl_system_status, 1, wx.EXPAND, 0)
label_22 = wx.StaticText(self, wx.ID_ANY, _("AC1 Status"))
sizer_8.Add(label_22, 0, 0, 0)
sizer_8.Add(self.text_ctrl_ac1_status, 1, wx.EXPAND, 0)
label_23 = wx.StaticText(self, wx.ID_ANY, _("DC2 Statu"))
sizer_8.Add(label_23, 0, 0, 0)
sizer_8.Add(self.text_ctrl_dc2_status, 1, wx.EXPAND, 0)
label_24 = wx.StaticText(self, wx.ID_ANY, _("DC3 Status"))
sizer_8.Add(label_24, 0, 0, 0)
sizer_8.Add(self.text_ctrl_dc3_status, 1, wx.EXPAND, 0)
sizer_7.Add(sizer_8, 1, wx.EXPAND, 0)
sizer_1.Add(sizer_7, 1, wx.EXPAND, 0)
sizer_3.Add(self.fault_grid, 0, wx.ALIGN_CENTER, 0)
label_25 = wx.StaticText(self, wx.ID_ANY, _("Fault Info (Documented)"))
sizer_3.Add(label_25, 0, 0, 0)
sizer_3.Add(self.text_fault_doc, 1, wx.EXPAND, 0)
label_26 = wx.StaticText(self, wx.ID_ANY, _("Fault Status"))
sizer_3.Add(label_26, 0, 0, 0)
sizer_3.Add(self.text_fault_status, 1, wx.EXPAND, 0)
sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
sizer_5.Add(self.button_2, 0, 0, 0)
sizer_5.Add(self.button_3, 0, 0, 0)
sizer_2.Add(sizer_5, 0, 0, 0)
label_8 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Control Method"))
grid_sizer_3.Add(label_8, 0, 0, 0)
grid_sizer_3.Add(self.choice_ac1_control, 0, 0, 0)
label_11 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Real Power Setpoint"))
grid_sizer_3.Add(label_11, 0, 0, 0)
grid_sizer_3.Add(self.text_ctrl_ac1_realpwr, 0, 0, 0)
label_12 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Reactive Power Setpoint"))
grid_sizer_3.Add(label_12, 0, 0, 0)
grid_sizer_3.Add(self.text_ctrl_ac1_reactpwr, 0, 0, 0)
sizer_9.Add(grid_sizer_3, 1, wx.EXPAND, 0)
sizer_2.Add(sizer_9, 1, wx.EXPAND, 0)
label_9 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Contol Method"))
grid_sizer_1.Add(label_9, 0, 0, 0)
grid_sizer_1.Add(self.choice_dc2_control, 0, 0, 0)
label_19 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Current Setpoint"))
grid_sizer_1.Add(label_19, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_dc2_current, 0, 0, 0)
label_13 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Power Setpoint"))
grid_sizer_1.Add(label_13, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_dc2_power, 0, 0, 0)
label_14 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Voltage Setpoint"))
grid_sizer_1.Add(label_14, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_dc2_voltage, 0, 0, 0)
label_17 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Precharge Limit Low"))
grid_sizer_1.Add(label_17, 0, 0, 0)
label_18 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Precharge Limit High"))
grid_sizer_1.Add(label_18, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_7, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_8, 0, 0, 0)
grid_sizer_1.Add(self.button_4, 0, 0, 0)
grid_sizer_1.Add(self.button_5, 0, 0, 0)
sizer_10.Add(grid_sizer_1, 1, wx.EXPAND, 0)
sizer_2.Add(sizer_10, 1, wx.EXPAND, 0)
label_10 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Control Method"))
grid_sizer_2.Add(label_10, 0, 0, 0)
grid_sizer_2.Add(self.choice_dc3_control, 0, 0, 0)
label_20 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Current Setpoint"))
grid_sizer_2.Add(label_20, 0, 0, 0)
grid_sizer_2.Add(self.text_ctrl_dc3_current, 0, 0, 0)
label_15 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Power Setpoint"))
grid_sizer_2.Add(label_15, 0, 0, 0)
grid_sizer_2.Add(self.text_ctrl_dc3_power, 0, 0, 0)
label_16 = wx.StaticText(self.panel_1, wx.ID_ANY, _("Voltage Setpoint"))
grid_sizer_2.Add(label_16, 0, 0, 0)
grid_sizer_2.Add(self.text_ctrl_dc3_voltage, 0, 0, 0)
sizer_11.Add(grid_sizer_2, 1, wx.ALL | wx.EXPAND, 1)
sizer_2.Add(sizer_11, 1, wx.EXPAND, 0)
self.panel_1.SetSizer(sizer_2)
sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
sizer_1.Add(self.property_grid_1, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
# end wxGlade
@ -125,6 +230,10 @@ class FaultFrame(wx.Frame):
print("Event handler 'OnButtonRemoteReset' not implemented!")
event.Skip()
def ToggleMonitoring(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'ToggleMonitoring' not implemented!")
event.Skip()
def OnCheckSysOpMode(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'OnCheckSysOpMode' not implemented!")
event.Skip()
@ -133,8 +242,12 @@ class FaultFrame(wx.Frame):
print("Event handler 'OnFaultSelect' not implemented!")
event.Skip()
def ToggleMonitoring(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'ToggleMonitoring' not implemented!")
def OnOpStart(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'OnOpStart' not implemented!")
event.Skip()
def OnOpStop(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'OnOpStop' not implemented!")
event.Skip()
# end of class FaultFrame

View file

@ -1,10 +1,10 @@
<?xml version="1.0"?>
<!-- generated by wxGlade 0.9.5 on Thu Feb 13 19:39:40 2020 -->
<!-- generated by wxGlade 0.9.5 on Tue Feb 18 18:24:41 2020 -->
<application encoding="UTF-8" for_version="3.0" header_extension=".h" indent_amount="4" indent_symbol="space" is_template="0" language="python" mark_blocks="0" option="0" overwrite="1" path="FaultView.py" source_extension=".cpp" top_window="frame" use_gettext="1" use_new_namespace="1">
<object class="FaultFrame" name="frame" base="EditFrame">
<size>558, 556</size>
<title>frame</title>
<size>1099, 729</size>
<title>PCS Controller</title>
<style>wxDEFAULT_FRAME_STYLE</style>
<object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer">
<orient>wxHORIZONTAL</orient>
@ -12,123 +12,200 @@
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxGridSizer" name="sizer_4" base="EditGridSizer">
<rows>7</rows>
<cols>2</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<object class="wxBoxSizer" name="sizer_7" base="EditBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_1" base="EditStaticText">
<label>IP Address</label>
<flag>wxEXPAND</flag>
<object class="wxGridSizer" name="sizer_4" base="EditGridSizer">
<rows>7</rows>
<cols>2</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_1" base="EditStaticText">
<label>IP Address</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_ip" base="EditTextCtrl">
<value>192.168.1.21</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_2" base="EditStaticText">
<label>Port</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_port" base="EditTextCtrl">
<value>502</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_3" base="EditStaticText">
<label>Unit ID</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_uid" base="EditTextCtrl">
<value>240</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_4" base="EditStaticText">
<label>Refresh Period (ms)</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_refresh" base="EditTextCtrl">
<value>2000</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="reset_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnReset</handler>
</events>
<label>Reset Connection</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="apply_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnApply</handler>
</events>
<label>Apply</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="rreset_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnButtonRemoteReset</handler>
</events>
<disabled>1</disabled>
<label>Remote PCS Reset</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxToggleButton" name="button_1" base="EditToggleButton">
<events>
<handler event="EVT_TOGGLEBUTTON">ToggleMonitoring</handler>
</events>
<disabled>1</disabled>
<label>Start</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="op_mode_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnCheckSysOpMode</handler>
</events>
<label>System OP Mode</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_op_mode" base="EditTextCtrl">
<style>wxTE_READONLY</style>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<option>1</option>
<border>0</border>
<object class="wxTextCtrl" name="input_ip" base="EditTextCtrl">
<value>192.168.1.21</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_2" base="EditStaticText">
<label>Port</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_port" base="EditTextCtrl">
<value>502</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_3" base="EditStaticText">
<label>Unit ID</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_uid" base="EditTextCtrl">
<value>240</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_4" base="EditStaticText">
<label>Refresh Period (ms)</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="input_refresh" base="EditTextCtrl">
<value>2000</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="reset_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnReset</handler>
</events>
<label>Reset Connection</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="apply_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnApply</handler>
</events>
<label>Apply</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="rreset_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnButtonRemoteReset</handler>
</events>
<label>Remote PCS Reset</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxToggleButton" name="button_1" base="EditToggleButton">
<events>
<handler event="EVT_TOGGLEBUTTON">ToggleMonitoring</handler>
</events>
<disabled>1</disabled>
<label>Start</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="op_mode_button" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnCheckSysOpMode</handler>
</events>
<label>System OP Mode</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_op_mode" base="EditTextCtrl">
<style>wxTE_READONLY</style>
<flag>wxEXPAND</flag>
<object class="wxBoxSizer" name="sizer_8" base="EditBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_21" base="EditStaticText">
<label>System Status</label>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxTextCtrl" name="text_ctrl_system_status" base="EditTextCtrl">
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_22" base="EditStaticText">
<label>AC1 Status</label>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxTextCtrl" name="text_ctrl_ac1_status" base="EditTextCtrl">
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_23" base="EditStaticText">
<label>DC2 Statu</label>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxTextCtrl" name="text_ctrl_dc2_status" base="EditTextCtrl">
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_24" base="EditStaticText">
<label>DC3 Status</label>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxTextCtrl" name="text_ctrl_dc3_status" base="EditTextCtrl">
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
</object>
</object>
</object>
</object>
@ -180,23 +257,358 @@
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_25" base="EditStaticText">
<label>Fault Info (Documented)</label>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxTextCtrl" name="text_fault_doc" base="EditTextCtrl">
<size>-1, 120</size>
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_26" base="EditStaticText">
<label>Fault Status</label>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxTextCtrl" name="text_fault_status" base="EditTextCtrl">
<size>-1, 120</size>
<style>wxTE_MULTILINE|wxTE_READONLY</style>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxPanel" name="panel_1" base="EditPanel">
<object class="wxBoxSizer" name="sizer_2" base="EditBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticBoxSizer" name="sizer_5" base="EditStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>Manual Mode Control</label>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="button_2" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnOpStart</handler>
</events>
<label>Start</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="button_3" base="EditButton">
<events>
<handler event="EVT_BUTTON">OnOpStop</handler>
</events>
<label>Stop</label>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxStaticBoxSizer" name="sizer_9" base="EditStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>AC1 Port</label>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxGridSizer" name="grid_sizer_3" base="EditGridSizer">
<rows>3</rows>
<cols>2</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_8" base="EditStaticText">
<label>Control Method</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxChoice" name="choice_ac1_control" base="EditChoice">
<selection>0</selection>
<choices>
<choice>IDLE</choice>
<choice>NET</choice>
<choice>GPWR</choice>
<choice>FPWR</choice>
</choices>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_11" base="EditStaticText">
<label>Real Power Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_ac1_realpwr" base="EditTextCtrl">
<value>0</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_12" base="EditStaticText">
<label>Reactive Power Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_ac1_reactpwr" base="EditTextCtrl">
<value>0</value>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxStaticBoxSizer" name="sizer_10" base="EditStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>DC2 Port</label>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxGridSizer" name="grid_sizer_1" base="EditGridSizer">
<rows>7</rows>
<cols>2</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_9" base="EditStaticText">
<label>Contol Method</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxChoice" name="choice_dc2_control" base="EditChoice">
<selection>0</selection>
<choices>
<choice>IDLE</choice>
<choice>NET</choice>
<choice>PV/MPPT</choice>
<choice>CURR</choice>
<choice>PWR</choice>
<choice>VOLT</choice>
</choices>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_19" base="EditStaticText">
<label>Current Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_dc2_current" base="EditTextCtrl">
<value>0</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_13" base="EditStaticText">
<label>Power Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_dc2_power" base="EditTextCtrl">
<value>0</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_14" base="EditStaticText">
<label>Voltage Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_dc2_voltage" base="EditTextCtrl">
<value>0</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_17" base="EditStaticText">
<label>Precharge Limit Low</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_18" base="EditStaticText">
<label>Precharge Limit High</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_7" base="EditTextCtrl">
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_8" base="EditTextCtrl">
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="button_4" base="EditButton">
<label>Enable Precharge</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxButton" name="button_5" base="EditButton">
<label>Disable Precharge</label>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxStaticBoxSizer" name="sizer_11" base="EditStaticBoxSizer">
<orient>wxHORIZONTAL</orient>
<label>DC3 Port</label>
<object class="sizeritem">
<option>1</option>
<border>1</border>
<flag>wxALL|wxEXPAND</flag>
<object class="wxGridSizer" name="grid_sizer_2" base="EditGridSizer">
<rows>4</rows>
<cols>2</cols>
<vgap>0</vgap>
<hgap>0</hgap>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_10" base="EditStaticText">
<label>Control Method</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxChoice" name="choice_dc3_control" base="EditChoice">
<selection>0</selection>
<choices>
<choice>IDLE</choice>
<choice>NET</choice>
<choice>PV/MPPT</choice>
<choice>CURR</choice>
<choice>PWR</choice>
<choice>VOLT</choice>
</choices>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_20" base="EditStaticText">
<label>Current Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_dc3_current" base="EditTextCtrl">
<value>0</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_15" base="EditStaticText">
<label>Power Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_dc3_power" base="EditTextCtrl">
<value>0</value>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxStaticText" name="label_16" base="EditStaticText">
<label>Voltage Setpoint</label>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<object class="wxTextCtrl" name="text_ctrl_dc3_voltage" base="EditTextCtrl">
<value>0</value>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxPropertyGridManager" name="property_grid_1" base="EditPropertyGridManager">
<extracode_post>self.property_grid_1.ShowHeader()</extracode_post>
<style>wxPG_TOOLBAR|wxPG_DESCRIPTION</style>
</object>
</object>
</object>
</object>
</application>

View file

@ -1,6 +1,10 @@
import easymodbus.modbusClient
from datetime import datetime as dt
from functools import reduce
from registers import regdict
import numpy as np
from pubsub import pub
nRegsPortStatus = 32
@ -20,6 +24,27 @@ addrStatusThermal = 0x0160
addrStatusDiagnostic = 0x0180
system_status = ["" for i in range(16)]
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"
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",
@ -29,8 +54,12 @@ p1_port_status = {0: "AC1 port is real power 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.",
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",
@ -71,30 +100,40 @@ p3_port_status = {0: "DC3 port is power soft-limiting",
14: "Reserved",
15: "Reserved"}
mode_dict = {
"IDLE": 0x0000,
"NET": 0x0001,
"GPWR": 0x0402,
"FPWR": 0x0502,
"PV/MPPT": 0x0002,
"CURR": 0x0301,
"PWR": 0x0401,
"VOLT": 0x0501,
}
def toPower(x):
return x * 10
return np.int16(x) * 10
def toVar(x):
return x * 10
return np.int16(x) * 10
def toVa(x):
return x * 10
return np.int16(x) * 10
def toPwrFactor(x):
return x * 0.01
return np.int16(x) * 0.01
def toCurrent(x):
return x * 0.1
return np.int16(x) * 0.1
def toVoltage(x):
return x
return np.int16(x)
def toFreq(x):
return x * 0.001
return np.uint16(x) * 0.001
def toTemperature(x):
return x * 0.1
return np.uint16(x) * 0.1
def toRpm(x):
return x
@ -139,11 +178,27 @@ def parse_address (addr_string):
return int(start, 16), nregisters
valueConversion = {"U16": np.uint16,
"S16": np.int16,
"HEX4": toBitString,
"HEX": toBitString,
"POWER": toPower,
"VAR": toVar,
"VA": toVa,
"PF": toPwrFactor,
"CURRENT": toCurrent,
"VOLTAGE": toVoltage,
"FREQ": toFreq,
"TEMP": toTemperature,
"RPM": toRpm,
"MINUTES": toMinutes,
"BAUD": toBaud,
"STRING": toString, }
class StabilitiRegister(object):
def __init__(self, name, proplist):
self.name = name
self.index = proplist[0]
self.index = list(map(int, proplist[0]))
self.address, self.size = parse_address(proplist[1])
self.access = proplist[2]
self.dtype = proplist[3]
@ -159,8 +214,11 @@ class StabilitiRegister(object):
def is_writable(self):
return 'W' in self.access
def convertValue(self, raw):
return valueConversion[self.dtype](raw)
def getdefaultvalue(self):
if self.vdefault = 'NA':
if self.vdefault == 'NA':
return None
else:
return self.vdefault
@ -170,7 +228,8 @@ 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 = {}
self.reg_info = {k:StabilitiRegister(k, v) for k, v in regdict.items()}
self.registers = np.zeros(4000, dtype=np.int)
def checkConnect(self):
if not self.client.is_connected():
@ -180,6 +239,39 @@ class StabilitiController(object):
if self.client.is_connected():
self.client.close()
def setPortModes(self, modes):
self.client.write_single_register(self.reg_info["p1_control_method"].address, mode_dict[modes[0]])
self.client.write_single_register(self.reg_info["p2_control_method"].address, mode_dict[modes[1]])
self.client.write_single_register(self.reg_info["p3_control_method"].address, mode_dict[modes[2]])
def setPortSetpoints(self, val):
for k,v in val.items():
self.client.write_single_register(self.reg_info[k].address, int(float(v)))
def setUserStart(self):
self.client.write_single_register(self.reg_info["user_start"].address, 1)
def setUserStop(self):
self.client.write_single_register(self.reg_info["user_stop"].address, 1)
def readAllRegisters(self):
print("read all registers")
self.checkConnect()
message_size = 64
for i in range(0, 654, message_size):
holdingRegisters = self.client.read_holdingregisters(i,message_size)
self.registers[i:i+message_size] = np.asarray(holdingRegisters)
for i in range(2000, 2069, message_size):
holdingRegisters = self.client.read_holdingregisters(i,message_size)
self.registers[i:i+message_size] = np.asarray(holdingRegisters)
pub.sendMessage("read_all_registers", reg=self.registers, info=self.reg_info)
def reg2str(self, r):
return toString(r)
@ -291,26 +383,18 @@ b3-b4: The status of the fault.
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
regs = self.registers
sys_dict = {k:v for k,v in self.reg_info.items() if v.index[0] == 4 and v.index[1] == 10}
system_all_status = {
k: v.convertValue(regs[v.address]) for k, v in sys_dict.items()
}
status = system_all_status['system_status']
return selectMessages(status, system_status), system_all_status
def getPortStatusAC1(self):
'''Get Status of AC1 Power Port'''
@ -318,7 +402,8 @@ system_status[15] PCS GFDI fault or IMI fault detected
def relAddr(x):
return x - addrStatusAC1
regs = self.client.read_holdingregisters(addrStatusAC1, nRegsPortStatus)
# regs = self.client.read_holdingregisters(addrStatusAC1, nRegsPortStatus)
regs = self.registers[addrStatusAC1:addrStatusAC1+nRegsPortStatus]
p1_all_status = {"p1_port_status": toBitString(regs[relAddr(96)]),
"p1_real_pwr_ramped": toPower(regs[relAddr(100)]),
@ -351,7 +436,8 @@ system_status[15] PCS GFDI fault or IMI fault detected
def relAddr(x):
return x - addrStatusDC2
regs = self.client.read_holdingregisters(addrStatusDC2, nRegsPortStatus)
# regs = self.client.read_holdingregisters(addrStatusDC2, nRegsPortStatus)
regs = self.registers[addrStatusDC2:addrStatusDC2+nRegsPortStatus]
p2_all_status = {'p2_port_status': toBitString(regs[relAddr(160)]),
'p2_current_ramped': toCurrent(regs[relAddr(164)]),
@ -375,7 +461,11 @@ system_status[15] PCS GFDI fault or IMI fault detected
def relAddr(x):
return x - addrStatusDC3
regs = self.client.read_holdingregisters(addrStatusDC3, nRegsPortStatus)
regs = self.registers[addrStatusDC3:addrStatusDC3+nRegsPortStatus]
# regs = self.client.read_holdingregisters(addrStatusDC3, nRegsPortStatus)
# self.registers[addrStatusDC3, nRegsPortStatus] = regs
p3_all_status = {'p3_port_status': toBitString(regs[relAddr(224)]),
'p3_current_ramped': toCurrent(regs[relAddr(228)]),
@ -390,4 +480,3 @@ system_status[15] PCS GFDI fault or IMI fault detected
status = p3_all_status['p3_port_status']
return selectMessages(status, p3_port_status), p3_all_status