36-cell (3-slave) voltage monitoring/logging version
This commit is contained in:
parent
915ca498fb
commit
b155a58374
6 changed files with 354 additions and 52 deletions
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (wxGladeTest)" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (bms-can-ui)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
||||||
2
.idea/wxGladeTest.iml
generated
2
.idea/wxGladeTest.iml
generated
|
|
@ -4,7 +4,7 @@
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="jdk" jdkName="Python 3.7 (bms-can-ui)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
127
BmsApp.py
127
BmsApp.py
|
|
@ -1,6 +1,10 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: UTF-8 -*-
|
# -*- coding: UTF-8 -*-
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import csv
|
||||||
|
import win32api
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
import wx.propgrid
|
import wx.propgrid
|
||||||
|
|
||||||
|
|
@ -13,13 +17,22 @@ from enum import Enum
|
||||||
import can
|
import can
|
||||||
import cantools
|
import cantools
|
||||||
|
|
||||||
from BmsView import BmsMonitorFrame
|
from VoltageView import BmsMonitorFrame
|
||||||
|
|
||||||
|
startTime = datetime.datetime.now()
|
||||||
|
winUptime_ms = win32api.GetTickCount()
|
||||||
|
winUptime_dt = datetime.timedelta(milliseconds=winUptime_ms)
|
||||||
|
bootTime = startTime-winUptime_dt
|
||||||
|
|
||||||
db = cantools.database.load_file('res/EBUS_Host.dbc')
|
db = cantools.database.load_file('res/EBUS_Host.dbc')
|
||||||
|
|
||||||
nModule = 22
|
nModule = 3
|
||||||
nCell = 12
|
nCell = 12
|
||||||
|
|
||||||
|
completeKey = "isModuleDataComplete"
|
||||||
|
timestampKey = "MessageTimestamp"
|
||||||
|
lastUpdateKey = timestampKey + ".old"
|
||||||
|
lastMsgKey = "LastMessageId"
|
||||||
|
|
||||||
def parse_can_id(arbitration_id):
|
def parse_can_id(arbitration_id):
|
||||||
mprefix = (arbitration_id & 0xfffff000) >> 12
|
mprefix = (arbitration_id & 0xfffff000) >> 12
|
||||||
|
|
@ -48,7 +61,7 @@ def find_category(imsg, isignal):
|
||||||
|
|
||||||
if 0x00 <= msg_type <= 0x06:
|
if 0x00 <= msg_type <= 0x06:
|
||||||
return BMS_MSG_CAT.BMS_PROFILE
|
return BMS_MSG_CAT.BMS_PROFILE
|
||||||
elif 0x07 <= msg_type <= 0x0B:
|
elif 0x07 <= msg_type <= 0x0C:
|
||||||
return BMS_MSG_CAT.MODULE_DATA
|
return BMS_MSG_CAT.MODULE_DATA
|
||||||
elif msg_type == 0x10:
|
elif msg_type == 0x10:
|
||||||
if isignal < 4:
|
if isignal < 4:
|
||||||
|
|
@ -84,7 +97,7 @@ class BmsListener (can.Listener):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
def on_message_received(self, msg):
|
def on_message_received(self, msg):
|
||||||
print("{:#X}".format(msg.arbitration_id))
|
# print("{:#X}".format(msg.arbitration_id))
|
||||||
self.parent.process_message(msg)
|
self.parent.process_message(msg)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -98,8 +111,31 @@ class Controller:
|
||||||
|
|
||||||
pub.subscribe (self.view.update_battery_module_grid, "bms.module.update")
|
pub.subscribe (self.view.update_battery_module_grid, "bms.module.update")
|
||||||
|
|
||||||
|
pub.subscribe(self.start_write, "view.start")
|
||||||
|
pub.subscribe(self.stop_write, "view.stop")
|
||||||
|
pub.subscribe (self.write_battery_module, "bms.module.update")
|
||||||
|
|
||||||
pub.subscribe (self.model.setter, "view.id_selector")
|
pub.subscribe (self.model.setter, "view.id_selector")
|
||||||
|
|
||||||
|
def start_write(self):
|
||||||
|
filename = self.view.text_ctrl_1.GetValue()
|
||||||
|
self.output_files = [open(filename+"-M{}.csv".format(i+1), 'w') for i in range(nModule)]
|
||||||
|
self.csv_writers = [csv.writer(output_file, delimiter=',') for output_file in self.output_files]
|
||||||
|
for csv_writer in self.csv_writers:
|
||||||
|
csv_writer.writerow(["time"] + ["CV{:02d}".format(i) for i in range(nCell)])
|
||||||
|
|
||||||
|
def stop_write(self):
|
||||||
|
for output_file in self.output_files:
|
||||||
|
output_file.close()
|
||||||
|
|
||||||
|
def write_battery_module(self, state, i_module):
|
||||||
|
module_dict = state[i_module]
|
||||||
|
if module_dict[lastMsgKey] & 0xff == 0x0c:
|
||||||
|
keyString = 'BatS_Cell{}_V'
|
||||||
|
voltages = [module_dict.get(keyString.format(x), -1) for x in range(nCell)]
|
||||||
|
dt = str(bootTime+datetime.timedelta(seconds=module_dict.get(timestampKey, 0.0)))
|
||||||
|
self.csv_writers[i_module].writerow([dt]+voltages)
|
||||||
|
|
||||||
|
|
||||||
class PmgrowBms:
|
class PmgrowBms:
|
||||||
def __init__(self, add_printer=True):
|
def __init__(self, add_printer=True):
|
||||||
|
|
@ -108,7 +144,7 @@ class PmgrowBms:
|
||||||
self.notifier = None
|
self.notifier = None
|
||||||
self.listeners = [can.Printer()] if add_printer else []
|
self.listeners = [can.Printer()] if add_printer else []
|
||||||
self.listeners.append(BmsListener(self))
|
self.listeners.append(BmsListener(self))
|
||||||
self.master_id = 0x02
|
self.master_id = 0x09
|
||||||
|
|
||||||
def setter (self, id):
|
def setter (self, id):
|
||||||
print ("updating master id")
|
print ("updating master id")
|
||||||
|
|
@ -128,17 +164,28 @@ class PmgrowBms:
|
||||||
self.notifier = None
|
self.notifier = None
|
||||||
self.bus = None
|
self.bus = None
|
||||||
|
|
||||||
def __update_bm_state(self, dmsg):
|
def __update_bm_state(self, dmsg, msg):
|
||||||
imodule = dmsg['BatS_Cell_ModuleNo']
|
i_module = dmsg['BatS_Cell_ModuleNo']
|
||||||
|
self.battery_module_state[i_module][lastUpdateKey] = self.battery_module_state[i_module].get(timestampKey,0.0)
|
||||||
|
self.battery_module_state[i_module][timestampKey] = msg.timestamp
|
||||||
|
self.battery_module_state[i_module][lastMsgKey] = msg.arbitration_id
|
||||||
|
|
||||||
|
if self.battery_module_state[i_module][timestampKey] - self.battery_module_state[i_module][lastUpdateKey] > 0.1:
|
||||||
|
self.battery_module_state[i_module][completeKey] = 4
|
||||||
|
else:
|
||||||
|
self.battery_module_state[i_module][completeKey] = self.battery_module_state[i_module][completeKey] - 1
|
||||||
|
|
||||||
for k in dmsg:
|
for k in dmsg:
|
||||||
self.battery_module_state[imodule][k] = dmsg[k]
|
self.battery_module_state[i_module][k] = dmsg[k]
|
||||||
|
|
||||||
|
return i_module
|
||||||
|
|
||||||
def process_message(self, msg):
|
def process_message(self, msg):
|
||||||
msg_prefix, master_id, msg_type = parse_can_id(msg.arbitration_id)
|
msg_prefix, master_id, msg_type = parse_can_id(msg.arbitration_id)
|
||||||
full_id = (msg_prefix, master_id, msg_type)
|
full_id = (msg_prefix, master_id, msg_type)
|
||||||
db_msg = db.get_message_by_frame_id(msg.arbitration_id)
|
db_msg = db.get_message_by_frame_id(msg.arbitration_id)
|
||||||
|
|
||||||
print(master_id, self.master_id)
|
# print(master_id, self.master_id)
|
||||||
if master_id == self.master_id:
|
if master_id == self.master_id:
|
||||||
if find_category(full_id, 0) == BMS_MSG_CAT.MODULE_DATA:
|
if find_category(full_id, 0) == BMS_MSG_CAT.MODULE_DATA:
|
||||||
try:
|
try:
|
||||||
|
|
@ -146,8 +193,8 @@ class PmgrowBms:
|
||||||
except KeyError as key:
|
except KeyError as key:
|
||||||
print(key, " does not exist")
|
print(key, " does not exist")
|
||||||
else:
|
else:
|
||||||
self.__update_bm_state(decoded)
|
i_module = self.__update_bm_state(decoded, msg)
|
||||||
pub.sendMessage("bms.module.update", state=self.battery_module_state)
|
pub.sendMessage("bms.module.update", state=self.battery_module_state, i_module=i_module)
|
||||||
|
|
||||||
elif find_category(full_id, 0) == BMS_MSG_CAT.BMS_PROFILE:
|
elif find_category(full_id, 0) == BMS_MSG_CAT.BMS_PROFILE:
|
||||||
pass
|
pass
|
||||||
|
|
@ -184,36 +231,6 @@ class BmsMonitorView(BmsMonitorFrame):
|
||||||
def __init__(self, *args, **kwds):
|
def __init__(self, *args, **kwds):
|
||||||
BmsMonitorFrame.__init__(self, *args, **kwds)
|
BmsMonitorFrame.__init__(self, *args, **kwds)
|
||||||
|
|
||||||
self.property_grid_page_info = self.property_grid_1.AddPage("Info")
|
|
||||||
|
|
||||||
for c in pgrid_category:
|
|
||||||
cat_name = c.name
|
|
||||||
cat = wx.propgrid.PropertyCategory(label=cat_name)
|
|
||||||
self.property_grid_page_info.Append(cat)
|
|
||||||
|
|
||||||
# bms_model = wx.propgrid.StringProperty(label="Model", name="bms_model", value="B3DWER32EW")
|
|
||||||
# self.property_grid_page_info.AppendIn("packdata", bms_model)
|
|
||||||
|
|
||||||
for msg in db.messages:
|
|
||||||
prefix, id, type = parse_can_id(msg.frame_id)
|
|
||||||
id_tuple = prefix, id, type
|
|
||||||
|
|
||||||
if id == 0x02:
|
|
||||||
|
|
||||||
if find_category(id_tuple, 0) == BMS_MSG_CAT.BMS_PROFILE:
|
|
||||||
prop = wx.propgrid.StringProperty(label=msg.name)
|
|
||||||
self.property_grid_page_info.AppendIn(BMS_MSG_CAT.BMS_PROFILE.name, prop)
|
|
||||||
|
|
||||||
for isig, signal in enumerate(msg.signals):
|
|
||||||
plabel = str_hex(type) + signal.name
|
|
||||||
prop = wx.propgrid.StringProperty(label=plabel)
|
|
||||||
prop.SetHelpString(signal.comment)
|
|
||||||
|
|
||||||
cat = find_category(id_tuple, isig)
|
|
||||||
|
|
||||||
if cat in pgrid_category:
|
|
||||||
self.property_grid_page_info.AppendIn(cat.name, prop)
|
|
||||||
|
|
||||||
def GetModuleVoltage(self, module_dict):
|
def GetModuleVoltage(self, module_dict):
|
||||||
keyString = 'BatS_Cell{}_V'
|
keyString = 'BatS_Cell{}_V'
|
||||||
return [module_dict.get(keyString.format(x), -1) for x in range(nCell)]
|
return [module_dict.get(keyString.format(x), -1) for x in range(nCell)]
|
||||||
|
|
@ -222,18 +239,28 @@ class BmsMonitorView(BmsMonitorFrame):
|
||||||
keyString = 'BatS_Cell{}_BalState'
|
keyString = 'BatS_Cell{}_BalState'
|
||||||
return [module_dict.get(keyString.format(x), -1) for x in range(nCell)]
|
return [module_dict.get(keyString.format(x), -1) for x in range(nCell)]
|
||||||
|
|
||||||
def update_battery_module_grid(self, state):
|
def update_battery_module_grid(self, state, i_module):
|
||||||
i_module = self.spin_ctrl_1.GetValue()
|
# grids = [self.grid_1, self.grid_2, self.grid_3]
|
||||||
|
ts_ctrls = [self.timestamp_1, self.timestamp_2, self.timestamp_3, ]
|
||||||
|
grid = self.grid_1
|
||||||
|
ts_ctrl = ts_ctrls[i_module]
|
||||||
module_dict = state[i_module]
|
module_dict = state[i_module]
|
||||||
voltages = self.GetModuleVoltage(module_dict)
|
if module_dict[lastMsgKey] & 0xff == 0x0c:
|
||||||
bal_states = self.GetModuleBalState(module_dict)
|
voltages = self.GetModuleVoltage(module_dict)
|
||||||
for i in range(nCell):
|
bal_states = self.GetModuleBalState(module_dict)
|
||||||
self.grid_1.SetCellValue(i, 0, str(voltages[i]))
|
dt = datetime.datetime.fromtimestamp(module_dict.get(timestampKey, 0.0))
|
||||||
self.grid_1.SetCellValue(i, 2, str(bal_states[i]))
|
msg_id = module_dict.get(lastMsgKey, 0)
|
||||||
self.grid_1.ForceRefresh()
|
ts_ctrl.SetValue(str(bootTime+datetime.timedelta(seconds=dt.timestamp())))
|
||||||
|
for i in range(nCell):
|
||||||
|
grid.SetCellValue(i, i_module, str(voltages[i]))
|
||||||
|
print("refreshing module ", i_module, "latest update: ", bootTime+datetime.timedelta(seconds=dt.timestamp()),
|
||||||
|
dt.timestamp(), "{:x}".format(msg_id))
|
||||||
|
grid.ForceRefresh()
|
||||||
|
|
||||||
def OnIdChoice(self, event):
|
def OnIdChoice(self, event):
|
||||||
print ("sending update request")
|
print ("sending update request")
|
||||||
|
# event.Get
|
||||||
|
# wx.Event.GetEventObject()
|
||||||
pub.sendMessage("view.id_selector", id=int(self.choice_1.GetStringSelection(), 16))
|
pub.sendMessage("view.id_selector", id=int(self.choice_1.GetStringSelection(), 16))
|
||||||
|
|
||||||
event.Skip()
|
event.Skip()
|
||||||
|
|
@ -253,7 +280,7 @@ class BmsMonitorView(BmsMonitorFrame):
|
||||||
|
|
||||||
class BmsApp(wx.App):
|
class BmsApp(wx.App):
|
||||||
def OnInit(self):
|
def OnInit(self):
|
||||||
self.bms = PmgrowBms()
|
self.bms = PmgrowBms(add_printer=True)
|
||||||
self.frame = BmsMonitorView(None, wx.ID_ANY, "")
|
self.frame = BmsMonitorView(None, wx.ID_ANY, "")
|
||||||
self.bms_controller = Controller(self.bms, self.frame)
|
self.bms_controller = Controller(self.bms, self.frame)
|
||||||
self.SetTopWindow(self.frame)
|
self.SetTopWindow(self.frame)
|
||||||
|
|
|
||||||
115
VoltageView.py
Normal file
115
VoltageView.py
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
#
|
||||||
|
# generated by wxGlade 0.9.6 on Sun Nov 29 07:00:24 2020
|
||||||
|
#
|
||||||
|
|
||||||
|
import wx
|
||||||
|
import wx.grid
|
||||||
|
|
||||||
|
# begin wxGlade: dependencies
|
||||||
|
import gettext
|
||||||
|
# end wxGlade
|
||||||
|
|
||||||
|
# begin wxGlade: extracode
|
||||||
|
# end wxGlade
|
||||||
|
|
||||||
|
|
||||||
|
class BmsMonitorFrame(wx.Frame):
|
||||||
|
def __init__(self, *args, **kwds):
|
||||||
|
# begin wxGlade: BmsMonitorFrame.__init__
|
||||||
|
kwds["style"] = kwds.get("style", 0) | wx.CAPTION | wx.CLIP_CHILDREN | wx.CLOSE_BOX | wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX | wx.SYSTEM_MENU
|
||||||
|
wx.Frame.__init__(self, *args, **kwds)
|
||||||
|
self.SetSize((338, 393))
|
||||||
|
self.button_1 = wx.ToggleButton(self, wx.ID_ANY, _("Start"))
|
||||||
|
self.text_ctrl_1 = wx.TextCtrl(self, wx.ID_ANY, _("prefix"))
|
||||||
|
self.timestamp_1 = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
|
||||||
|
self.timestamp_2 = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
|
||||||
|
self.timestamp_3 = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
|
||||||
|
self.grid_1 = wx.grid.Grid(self, wx.ID_ANY, size=(1, 1))
|
||||||
|
|
||||||
|
self.__set_properties()
|
||||||
|
self.__do_layout()
|
||||||
|
|
||||||
|
self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggle, self.button_1)
|
||||||
|
# end wxGlade
|
||||||
|
|
||||||
|
def __set_properties(self):
|
||||||
|
# begin wxGlade: BmsMonitorFrame.__set_properties
|
||||||
|
self.SetTitle(_("BMS Monitor"))
|
||||||
|
_icon = wx.NullIcon
|
||||||
|
_icon.CopyFromBitmap(wx.Bitmap("res\\repurpose-energy-ci-icon.ico", wx.BITMAP_TYPE_ANY))
|
||||||
|
self.SetIcon(_icon)
|
||||||
|
self.grid_1.CreateGrid(12, 3)
|
||||||
|
self.grid_1.EnableEditing(0)
|
||||||
|
self.grid_1.EnableDragColSize(0)
|
||||||
|
self.grid_1.EnableDragRowSize(0)
|
||||||
|
self.grid_1.EnableDragGridSize(0)
|
||||||
|
self.grid_1.SetColLabelValue(0, _("Slave 1 (V)"))
|
||||||
|
self.grid_1.SetColLabelValue(1, _("Slave 2 (V)"))
|
||||||
|
self.grid_1.SetColLabelValue(2, _("Slave 3 (V)"))
|
||||||
|
self.grid_1.SetRowLabelValue(0, _("Cell 1"))
|
||||||
|
self.grid_1.SetRowLabelValue(1, _("Cell 2"))
|
||||||
|
self.grid_1.SetRowLabelValue(2, _("Cell 3"))
|
||||||
|
self.grid_1.SetRowLabelValue(3, _("Cell 4"))
|
||||||
|
self.grid_1.SetRowLabelValue(4, _("Cell 5"))
|
||||||
|
self.grid_1.SetRowLabelValue(5, _("Cell 6"))
|
||||||
|
self.grid_1.SetRowSize(5, 18)
|
||||||
|
self.grid_1.SetRowLabelValue(6, _("Cell 7"))
|
||||||
|
self.grid_1.SetRowLabelValue(7, _("Cell 8"))
|
||||||
|
self.grid_1.SetRowLabelValue(8, _("Cell 9"))
|
||||||
|
self.grid_1.SetRowLabelValue(9, _("Cell 10"))
|
||||||
|
self.grid_1.SetRowLabelValue(10, _("Cell 11"))
|
||||||
|
self.grid_1.SetRowLabelValue(11, _("Cell 12"))
|
||||||
|
# end wxGlade
|
||||||
|
|
||||||
|
def __do_layout(self):
|
||||||
|
# begin wxGlade: BmsMonitorFrame.__do_layout
|
||||||
|
sizer_1 = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
sizer_6.Add(self.button_1, 0, 0, 0)
|
||||||
|
sizer_6.Add((20, 20), 0, 0, 0)
|
||||||
|
label_4 = wx.StaticText(self, wx.ID_ANY, _("Output: "))
|
||||||
|
sizer_6.Add(label_4, 0, 0, 0)
|
||||||
|
sizer_6.Add(self.text_ctrl_1, 0, 0, 0)
|
||||||
|
sizer_1.Add(sizer_6, 0, wx.EXPAND, 0)
|
||||||
|
label_1 = wx.StaticText(self, wx.ID_ANY, _("Slave 1 Update "))
|
||||||
|
sizer_2.Add(label_1, 0, 0, 0)
|
||||||
|
sizer_2.Add(self.timestamp_1, 1, 0, 0)
|
||||||
|
sizer_1.Add(sizer_2, 0, wx.EXPAND, 0)
|
||||||
|
label_2 = wx.StaticText(self, wx.ID_ANY, _("Slave 2 Update "))
|
||||||
|
sizer_3.Add(label_2, 0, 0, 0)
|
||||||
|
sizer_3.Add(self.timestamp_2, 1, wx.EXPAND, 0)
|
||||||
|
sizer_1.Add(sizer_3, 0, wx.EXPAND, 0)
|
||||||
|
label_3 = wx.StaticText(self, wx.ID_ANY, _("Slave 3 Update "))
|
||||||
|
sizer_4.Add(label_3, 0, 0, 0)
|
||||||
|
sizer_4.Add(self.timestamp_3, 2, wx.EXPAND, 0)
|
||||||
|
sizer_1.Add(sizer_4, 0, wx.EXPAND, 0)
|
||||||
|
sizer_1.Add(self.grid_1, 1, wx.EXPAND, 0)
|
||||||
|
self.SetSizer(sizer_1)
|
||||||
|
self.Layout()
|
||||||
|
# end wxGlade
|
||||||
|
|
||||||
|
def OnToggle(self, event): # wxGlade: BmsMonitorFrame.<event_handler>
|
||||||
|
print("Event handler 'OnToggle' not implemented!")
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
# end of class BmsMonitorFrame
|
||||||
|
|
||||||
|
class BmsApp(wx.App):
|
||||||
|
def OnInit(self):
|
||||||
|
self.frame = BmsMonitorFrame(None, wx.ID_ANY, "")
|
||||||
|
self.SetTopWindow(self.frame)
|
||||||
|
self.frame.Show()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# end of class BmsApp
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
gettext.install("app") # replace with the appropriate catalog name
|
||||||
|
|
||||||
|
app = BmsApp(0)
|
||||||
|
app.MainLoop()
|
||||||
155
VoltageView.wxg
Normal file
155
VoltageView.wxg
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- generated by wxGlade 0.9.6 on Sun Nov 29 07:00:21 2020 -->
|
||||||
|
|
||||||
|
<application class="BmsApp" encoding="UTF-8" for_version="3.0" header_extension=".h" indent_amount="4" indent_symbol="space" is_template="0" language="python" mark_blocks="1" name="app" option="0" overwrite="1" path="./VoltageView.py" source_extension=".cpp" top_window="frame" use_gettext="1" use_new_namespace="1">
|
||||||
|
<object class="BmsMonitorFrame" name="frame" base="EditFrame">
|
||||||
|
<size>338, 393</size>
|
||||||
|
<title>BMS Monitor</title>
|
||||||
|
<style>wxCAPTION|wxMINIMIZE_BOX|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxSYSTEM_MENU|wxCLIP_CHILDREN</style>
|
||||||
|
<icon>res\repurpose-energy-ci-icon.ico</icon>
|
||||||
|
<object class="wxBoxSizer" name="sizer_1" base="EditBoxSizer">
|
||||||
|
<orient>wxVERTICAL</orient>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxBoxSizer" name="sizer_6" base="EditBoxSizer">
|
||||||
|
<orient>wxHORIZONTAL</orient>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxToggleButton" name="button_1" base="EditToggleButton">
|
||||||
|
<events>
|
||||||
|
<handler event="EVT_TOGGLEBUTTON">OnToggle</handler>
|
||||||
|
</events>
|
||||||
|
<label>Start</label>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="spacer" name="spacer" base="EditSpacer">
|
||||||
|
<width>20</width>
|
||||||
|
<height>20</height>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxStaticText" name="label_4" base="EditStaticText">
|
||||||
|
<label>Output: </label>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxTextCtrl" name="text_ctrl_1" base="EditTextCtrl">
|
||||||
|
<value>prefix</value>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxBoxSizer" name="sizer_2" base="EditBoxSizer">
|
||||||
|
<orient>wxHORIZONTAL</orient>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxStaticText" name="label_1" base="EditStaticText">
|
||||||
|
<label>Slave 1 Update </label>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>1</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxTextCtrl" name="timestamp_1" base="EditTextCtrl">
|
||||||
|
<style>wxTE_READONLY</style>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxBoxSizer" name="sizer_3" base="EditBoxSizer">
|
||||||
|
<orient>wxHORIZONTAL</orient>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxStaticText" name="label_2" base="EditStaticText">
|
||||||
|
<label>Slave 2 Update </label>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>1</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxTextCtrl" name="timestamp_2" base="EditTextCtrl">
|
||||||
|
<style>wxTE_READONLY</style>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxBoxSizer" name="sizer_4" base="EditBoxSizer">
|
||||||
|
<orient>wxHORIZONTAL</orient>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>0</option>
|
||||||
|
<border>0</border>
|
||||||
|
<object class="wxStaticText" name="label_3" base="EditStaticText">
|
||||||
|
<label>Slave 3 Update </label>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>2</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxTextCtrl" name="timestamp_3" base="EditTextCtrl">
|
||||||
|
<style>wxTE_READONLY</style>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="sizeritem">
|
||||||
|
<option>1</option>
|
||||||
|
<border>0</border>
|
||||||
|
<flag>wxEXPAND</flag>
|
||||||
|
<object class="wxGrid" name="grid_1" base="EditGrid">
|
||||||
|
<create_grid>1</create_grid>
|
||||||
|
<columns>
|
||||||
|
<column size="-1">Slave 1 (V)</column>
|
||||||
|
<column size="-1">Slave 2 (V)</column>
|
||||||
|
<column size="-1">Slave 3 (V)</column>
|
||||||
|
</columns>
|
||||||
|
<rows>
|
||||||
|
<row size="-1">Cell 1</row>
|
||||||
|
<row size="-1">Cell 2</row>
|
||||||
|
<row size="-1">Cell 3</row>
|
||||||
|
<row size="-1">Cell 4</row>
|
||||||
|
<row size="-1">Cell 5</row>
|
||||||
|
<row size="18">Cell 6</row>
|
||||||
|
<row size="-1">Cell 7</row>
|
||||||
|
<row size="-1">Cell 8</row>
|
||||||
|
<row size="-1">Cell 9</row>
|
||||||
|
<row size="-1">Cell 10</row>
|
||||||
|
<row size="-1">Cell 11</row>
|
||||||
|
<row size="-1">Cell 12</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>
|
||||||
|
</object>
|
||||||
|
</application>
|
||||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
wxPython~=4.1.0
|
||||||
|
python-can~=3.3.3
|
||||||
|
cantools~=35.3.0
|
||||||
|
pywin32~=300
|
||||||
|
Pypubsub~=4.0.3
|
||||||
Loading…
Add table
Reference in a new issue