Initial Commit - Fault Monitoring

This commit is contained in:
Yeongdo Park 2020-02-10 20:18:39 -08:00
commit 64580f8f8a
13 changed files with 1045 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/venv/
*.bak
/__pycache__/

2
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml

View file

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (modbus-test)" project-jdk-type="Python SDK" />
</project>

10
.idea/modbus-test.iml generated Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modbus-test.iml" filepath="$PROJECT_DIR$/.idea/modbus-test.iml" />
</modules>
</component>
</project>

7
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

160
FaultMonitor.py Normal file
View file

@ -0,0 +1,160 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.5 on Fri Feb 7 20:10:41 2020
#
import wx
import wx.grid
import gettext
gettext.install(None)
from pubsub import pub
print('pubsub API version', pub.VERSION_API)
from pubsub.utils.notification import useNotifyByWriteFile
import sys
useNotifyByWriteFile(sys.stdout)
import pprint
from stabiliti import StabilitiController as SC
from faults import faultInfo
from FaultView import FaultFrame
class Controller:
def __init__(self, view):
self.sc = None
self.view = view
self.timer = wx.Timer()
self.timer.Bind(wx.EVT_TIMER, self.OnTimer)
pub.subscribe(self.getFaultInfo, 'fault_selected')
pub.subscribe(self.startTimer, 'monitoring_started')
pub.subscribe(self.stopTimer, 'monitoring_stopped')
pub.subscribe(self.applyNetworkConfigs, 'apply_network_configs')
pub.subscribe(self.resetNetworkConfigs, 'reset_network_configs')
def startTimer(self):
self.timer.Start(2000)
def stopTimer(self):
self.timer.Stop()
def applyNetworkConfigs(self, ncDict):
if self.sc:
self.sc.checkClose()
self.sc = SC(**ncDict)
def resetNetworkConfigs(self):
if self.sc:
self.sc.checkClose()
self.sc = None
def getFaultInfo(self, pos):
y, x = pos
fid = x + y*8
if 0 <= fid <= 63:
try:
info_text = faultInfo[fid]
except IndexError:
info_text = "Fault Number: {} (Reserved)".format(fid)
self.view.text_fault_doc.SetValue(info_text)
status_text = "Not Connected"
if self.sc:
fDict = self.sc.readFaultDetail(fid)
status_text = pprint.pformat(fDict)
self.view.text_fault_status.SetValue(status_text)
def OnTimer(self, event):
factivity = self.sc.readFaultActivity()
foccurence = self.sc.readFaultOccurence()
self.view.SetFaultGrid(factivity, foccurence)
event.Skip()
class MyFrame(FaultFrame):
def __init__(self, *args, **kwds):
FaultFrame.__init__(self, *args, **kwds)
def OnFaultSelect(self, event): # wxGlade: MyFrame.<event_handler>
pub.sendMessage("fault_selected", pos=(event.GetRow(), event.GetCol()))
event.Skip()
def SetFaultGrid(self, fActivity, fOccurence):
if len(fActivity) == len(fOccurence) == 64:
for i in range(8):
for j in range(8):
if fActivity[i*8+j] == '1':
self.fault_grid.SetCellBackgroundColour(i, j, wx.LIGHT_GREY)
if fOccurence[i*8+j] == '1':
self.fault_grid.SetCellValue(i, j, "O")
def ToggleMonitoring(self, event): # wxGlade: MyFrame.<event_handler>
btnLabel = self.button_1.GetLabel()
if self.button_1.Value:
pub.sendMessage("monitoring_started")
self.button_1.SetLabel("Stop")
else:
pub.sendMessage("monitoring_stopped")
self.button_1.SetLabel("Start")
if event:
event.Skip()
def OnApply(self, event):
if self.button_1.Enabled:
return
self.input_uid.Disable()
self.input_port.Disable()
self.input_ip.Disable()
self.input_refresh.Disable()
ncDict = {
"ipaddr": self.input_ip.GetValue(),
"port": int(self.input_port.GetValue()),
"uid": int(self.input_uid.GetValue()),
}
pub.sendMessage("apply_network_configs", ncDict=ncDict)
self.button_1.Enable()
def OnReset(self, event):
if not self.button_1.Enabled:
return
pub.sendMessage("reset_network_configs")
self.button_1.SetValue(False)
self.ToggleMonitoring(None)
self.button_1.Disable()
self.input_uid.Enable()
self.input_port.Enable()
self.input_ip.Enable()
self.input_refresh.Enable()
# end of class MyFrame
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.c = Controller(self.frame)
self.SetTopWindow(self.frame)
self.frame.Show()
return True
# end of class MyApp
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()
app.c.sc.checkClose()

122
FaultView.py Normal file
View file

@ -0,0 +1,122 @@
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.5 on Mon Feb 10 19:42:48 2020
#
import wx
import wx.grid
# begin wxGlade: dependencies
import gettext
# end wxGlade
# begin wxGlade: extracode
# end wxGlade
class FaultFrame(wx.Frame):
def __init__(self, *args, **kwds):
# 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.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"))
self.input_refresh = wx.TextCtrl(self, wx.ID_ANY, _("2000"))
self.reset_button = wx.Button(self, wx.ID_ANY, _("Reset"))
self.apply_button = wx.Button(self, wx.ID_ANY, _("Apply"))
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.__set_properties()
self.__do_layout()
self.Bind(wx.EVT_BUTTON, self.OnReset, self.reset_button)
self.Bind(wx.EVT_BUTTON, self.OnApply, self.apply_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)
# end wxGlade
def __set_properties(self):
# begin wxGlade: FaultFrame.__set_properties
self.SetTitle(_("frame"))
self.fault_grid.CreateGrid(8, 8)
self.fault_grid.SetRowLabelSize(30)
self.fault_grid.SetColLabelSize(30)
self.fault_grid.EnableEditing(0)
self.fault_grid.EnableDragColSize(0)
self.fault_grid.EnableDragRowSize(0)
self.fault_grid.EnableDragGridSize(0)
self.fault_grid.SetColSize(0, 30)
self.fault_grid.SetColSize(1, 30)
self.fault_grid.SetColSize(2, 30)
self.fault_grid.SetColSize(3, 30)
self.fault_grid.SetColSize(4, 30)
self.fault_grid.SetColSize(5, 30)
self.fault_grid.SetColSize(6, 30)
self.fault_grid.SetColSize(7, 30)
self.fault_grid.SetRowSize(0, 30)
self.fault_grid.SetRowSize(1, 30)
self.fault_grid.SetRowSize(2, 30)
self.fault_grid.SetRowSize(3, 30)
self.fault_grid.SetRowSize(4, 30)
self.fault_grid.SetRowSize(5, 30)
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))
# end wxGlade
def __do_layout(self):
# begin wxGlade: FaultFrame.__do_layout
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_3 = wx.BoxSizer(wx.VERTICAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_4 = wx.GridSizer(5, 2, 0, 0)
label_1 = wx.StaticText(self, wx.ID_ANY, _("IP Address"))
sizer_4.Add(label_1, 0, 0, 0)
sizer_4.Add(self.input_ip, 0, 0, 0)
label_2 = wx.StaticText(self, wx.ID_ANY, _("Port"))
sizer_4.Add(label_2, 0, 0, 0)
sizer_4.Add(self.input_port, 0, 0, 0)
label_3 = wx.StaticText(self, wx.ID_ANY, _("Unit ID"))
sizer_4.Add(label_3, 0, 0, 0)
sizer_4.Add(self.input_uid, 0, 0, 0)
label_4 = wx.StaticText(self, wx.ID_ANY, _("Refresh Period (ms)"))
sizer_4.Add(label_4, 0, 0, 0)
sizer_4.Add(self.input_refresh, 0, 0, 0)
sizer_4.Add(self.reset_button, 0, 0, 0)
sizer_4.Add(self.apply_button, 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_1.Add(sizer_3, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
# end wxGlade
def OnReset(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'OnReset' not implemented!")
event.Skip()
def OnApply(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'OnApply' not implemented!")
event.Skip()
def OnFaultSelect(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'OnFaultSelect' not implemented!")
event.Skip()
def ToggleMonitoring(self, event): # wxGlade: FaultFrame.<event_handler>
print("Event handler 'ToggleMonitoring' not implemented!")
event.Skip()
# end of class FaultFrame

184
faultView.wxg Normal file
View file

@ -0,0 +1,184 @@
<?xml version="1.0"?>
<!-- generated by wxGlade 0.9.5 on Mon Feb 10 19:42:46 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>632, 556</size>
<title>frame</title>
<style>wxDEFAULT_FRAME_STYLE</style>
<object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxGridSizer" name="sizer_4" base="EditGridSizer">
<rows>5</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</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>
</object>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxEXPAND</flag>
<object class="wxBoxSizer" name="sizer_3" base="EditBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>1</option>
<border>0</border>
<flag>wxALIGN_CENTER</flag>
<object class="wxBoxSizer" name="sizer_2" base="EditBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<flag>wxALIGN_CENTER</flag>
<object class="wxGrid" name="fault_grid" base="EditGrid">
<events>
<handler event="EVT_GRID_CMD_CELL_LEFT_CLICK">OnFaultSelect</handler>
</events>
<size>270, 270</size>
<create_grid>1</create_grid>
<columns>
<column size="30">A</column>
<column size="30">B</column>
<column size="30">C</column>
<column size="30">D</column>
<column size="30">E</column>
<column size="30">F</column>
<column size="30">G</column>
<column size="30">H</column>
</columns>
<rows>
<row size="30">0</row>
<row size="30">1</row>
<row size="30">2</row>
<row size="30">3</row>
<row size="30">4</row>
<row size="30">5</row>
<row size="30">6</row>
<row size="30">7</row>
</rows>
<enable_editing>0</enable_editing>
<enable_grid_lines>1</enable_grid_lines>
<enable_col_resize>0</enable_col_resize>
<enable_row_resize>0</enable_row_resize>
<enable_grid_resize>0</enable_grid_resize>
<selection_mode>wxGrid.wxGridSelectCells</selection_mode>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<border>0</border>
<flag>wxALIGN_CENTER</flag>
<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>
</object>
<object class="sizeritem">
<option>0</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>
<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>
</object>
</application>

372
faults.py Normal file
View file

@ -0,0 +1,372 @@
faultInfo = [
'''\
Fault Number: 0
Description: GFDI fault (grounded DC)
Selector Values:
0x01 = GFDI fault detected
0x10 = Loss of communication
Severity: 0x110 = Lockdown
''',
'''\
Fault Number: 1
Description: IMI fault (floating DC)
Selector Values: NA
Severity: 0x110 = Lockdown
''',
'''\
Fault Number: 2
Description: Power module heatsink temperature fault
Selector Values:
0x00 = Over temperature
0x01 = Under temperature
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 3
Description: Control board temperature fault
Selector Values:
0x00 = Over temperature
0x01 = Under temperature
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 4
Description: 24V auxiliary supply under voltage
Selector Values: NA
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 5
Description: Fan fault
Selector Values:
0x00 = Fan not spinning
0x01 = Bad tach reading
Severity: 0x110 = Lockdown
''',
'''\
Fault Number: 6
Description: DC differential over voltage
Selector Values:
0x00 = Port 2
0x01 = Port 3
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 7
Description: DC differential under voltage
Selector Values:
0x00 = Port 2
0x01 = Port 3
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 8
Description: Link over voltage
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 9
Description: Link starving
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 10
Description: Link over current
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 11
Description: IGBT VCES over voltage 1
Selector Values:
0x00 = Link positive to phase A
0x01 = Link positive to phase B
0x10 = Link positive to phase C
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 12
Description: IGBT VCES over voltage 2
Selector Values:
0x00 = Link negative to phase A
0x01 = Link negative to phase B
0x10 = Link negative to phase C
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 13
Description: IGBT VCES over voltage 3
Selector Values:
0x00 = Link positive to DC port 2
0x01 = Link positive to DC port 3
0x10 = Link positive to DC common
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 14
Description: IGBT VCES over voltage 4
Selector Values:
0x00 = Link positive to DC port 2
0x01 = Link positive to DC port 3
0x10 = Link positive to DC common
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 15
Description: AC A-B hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 16
Description: AC B-C hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 17
Description: AC C-A hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 18
Description: DC2 input hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 19
Description: DC2 output hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 20
Description: DC3 input hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 21
Description: DC3 output hard switch
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 22
Description: Link state timer check
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 23
Description: Bad link start
Selector Values: 0x00, 0x01, 0x10, 0x11
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 24
Description: Invalid method/settings
Selector Values:
0x00 = Invalid port1 method/setting
0x01 = Invalid port2 method/setting
0x10 = Invalid port3 method/setting
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 25
Description: Island detected
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 26
Description: AC under voltage level 1 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 27
Description: AC under voltage level 2 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 28
Description: AC under voltage level 3 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 29
Description: AC under voltage level 4 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 30
Description: AC over voltage level 1 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 31
Description: AC over voltage level 2 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 32
Description: AC over voltage level 3 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 33
Description: AC over voltage level 4 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 34
Description: AC under frequency level 1 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 35
Description: AC under frequency level 2 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 36
Description: AC under frequency level 3 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 37
Description: AC under frequency level 4 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 38
Description: AC over frequency level 1 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 39
Description: AC over frequency level 2 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 40
Description: AC over frequency level 3 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 41
Description: AC over frequency level 4 trip
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 42
Description: Watchdog timeout
Selector Values: 0x00, 0x01
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 43
Description: Emergency stop active
Selector Values: NA
Severity: 0x011 = Abort 0
''',
'''\
Fault Number: 44
Description: Sensing fault
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 45
Description: Arc fault
Selector Values: NA
Severity: 0x011 Abort 0
''',
'''\
Fault Number: 46
Description: Comms processor initiated shutdown
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 47
Description: Surge detect
Selector Values:
0x00 = Phase A
0x01 = Phase B
0x10 = Phase C
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 48
Description: AC switch breakdown voltage exceeded
Selector Values:
0x00 = Phase A to phase B
0x01 = Phase B to phase C
0x10 = Phase C to phase A
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 49
Description: DC switch breakdown voltage exceeded
Selector Values:
0x00 = DC2
0x01 = DC3
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 50
Description: Precharge timeout
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 51
Description: AC to link primary high voltage
Selector Values:
0x000 = Positive to ground
0x001 = Negative to ground
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 52
Description: AC line to line instantaneous over voltage
Selector Values:
0x000 = Phase A to phase B
0x001 = Phase B to phase C
0x010 = Phase C to phase A
Severity: 0x100 Abort 1
''',
'''\
Fault Number: 53
Description: License fault
Selector Values: NA
Severity: 0x101 Abort 2
''',
'''\
Fault Number: 54
Description: Grid_Ack timeout
Selector Values: NA
Severity: 0x100 Abort 1
'''
]

122
stabiliti.py Normal file
View file

@ -0,0 +1,122 @@
import easymodbus.modbusClient
from datetime import datetime as dt
from functools import reduce
class StabilitiController(object):
''''''
def __init__(self, ipaddr, port=502, uid=240):
self.client = easymodbus.modbusClient.ModbusClient(ipaddr, port)
self.client.unitidentifier = uid
def checkConnect(self):
if not self.client.is_connected():
self.client.connect()
def checkClose(self):
if self.client.is_connected():
self.client.close()
def reg2str(self, r):
ms = (r & 0xff00) >> 8
ls = (r & 0xff)
return chr(ms) + chr(ls)
def getNetworkConfigs(self, config=None):
self.checkConnect()
configDict = {}
from functools import reduce
if config:
pass
else:
holdingRegisters = self.client.read_holdingregisters(2030,8)
configDict["ipaddr"] = (reduce (lambda a, b: str(a)+str(b), map(self.reg2str, holdingRegisters)))
holdingRegisters = self.client.read_holdingregisters(2038,8)
configDict["netmask"] = (reduce (lambda a, b: str(a)+str(b), map(self.reg2str, holdingRegisters)))
return configDict
def reg2utc(self, timel, timeu):
return dt.utcfromtimestamp((timeu << 16) + timel)
def reg2bits(self, reg):
return bin(reg)[2:].zfill(16)
def readFaultDetail(self, findex):
if not (0<=findex<=63):
return None
self.checkConnect()
self.client.write_single_register(0, findex)
regs = self.client.read_holdingregisters(1, 9)
flimit, fval, fcount, ftimel, ftimeu = regs[:5]
fselector, fstatus = regs[-2:]
fselector = bin(fselector)[2:].zfill(16)[-3:]
print(bin(fstatus)[2:].zfill(16))
fseverity = bin(fstatus)[2:].zfill(16)[-3:]
'''
b0-b2: The severity of the fault.
0x000 = Info: increments the fault counter only.
0x001 = Alert: increments the fault counter only.
0x010 = Alarm: fault is logged.
0x011 = Abort 0: fault is logged and unit is stopped. Reconnect timer 0 is used for restart.
0x100 = Abort 1: fault is logged and unit is stopped. Reconnect timer 1 is used for restart.
0x101 = Abort 2: fault is logged and unit is stopped. Reconnect timer 2 is used for restart.
0x110 = Lockdown: fault is logged, unit stops processing power and requires a reset.
0x111 = Reserved
'''
fstatus = bin(fstatus)[2:].zfill(16)[-5:-3]
'''
b3-b4: The status of the fault.
0x01 = No fault
0x10 = Active
0x11 = Occurred
'''
print(flimit, fval, fcount,
self.reg2utc(ftimel, ftimeu),
fselector,
fstatus,
fseverity
)
return {
"Number": findex,
"Limit": flimit,
"Value": fval,
"Occurence": fcount,
"TimeStamp": self.reg2utc(ftimel, ftimeu),
"Selector": fselector,
"Severity": fseverity,
"Status": fstatus,
}
def readFaultArray(self, start):
import operator as op
self.checkConnect()
faults = self.client.read_holdingregisters(start,4)
faultStrings = map(lambda x: bin(x)[2:].zfill(16)[::-1], faults)
return reduce(op.add, faultStrings)
def readFaultActivity(self):
return self.readFaultArray(16)
def readFaultOccurence(self):
return self.readFaultArray(24)
def printAllFaults(self, faults):
fmt = " {} || {} | {} | {} | {} | {} | {} | {} | {} "
sep = " ================================== "
print (fmt.format(" ", *list(range(8))))
print (sep)
for i in range(8):
idx = i * 8
print (fmt.format(i, *faults[idx:idx+8]))
def reconnectTimer(self):
pass
def getSystemStatus(self):
pass

45
test1.py Normal file
View file

@ -0,0 +1,45 @@
import easymodbus.modbusClient
ipaddr, port = ('192.168.1.21', 502)
uid = 240
modbusclient = easymodbus.modbusClient.ModbusClient(ipaddr, port)
# modbusclient.timeout = 5000
modbusclient.unitidentifier = uid
modbusclient.connect()
modbusclient.is_connected()
# holdingRegisters = easymodbus.modbusClient.convert_registers_to_float(modbusclient.read_holdingregisters(2038,8))
# print (holdingRegisters)
def reg2str (r):
ms = (r & 0xff00) >> 8
ls = (r & 0xff)
return chr(ms) + chr(ls)
from functools import reduce
holdingRegisters = modbusclient.read_holdingregisters(296,1)
print(hex(holdingRegisters[0]))
holdingRegisters = modbusclient.read_holdingregisters(297,1)
print(holdingRegisters)
modbusclient.close()
from stabiliti import StabilitiController as SC
sc = SC(ipaddr)
sc.getNetworkConfigs()
sc.printAllFaults(sc.readFaultActivity())
sc.printAllFaults(sc.readFaultOccurence())
print (
list(filter (lambda x: x[1] == '1', enumerate(sc.readFaultActivity())))
)
sc.checkClose()