Erster Stand der Hintergrundprozesse, die auf der Synology unter /volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins Web-Verzeichnis. Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot), zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat. Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py, gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte. Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein pip, sie muessen neben den Skripten liegen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
294 lines
13 KiB
Python
294 lines
13 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# A serial port configuration dialog for wxPython. A number of flags can
|
|
# be used to configure the fields that are displayed.
|
|
#
|
|
# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
import wx
|
|
import serial
|
|
import serial.tools.list_ports
|
|
|
|
SHOW_BAUDRATE = 1 << 0
|
|
SHOW_FORMAT = 1 << 1
|
|
SHOW_FLOW = 1 << 2
|
|
SHOW_TIMEOUT = 1 << 3
|
|
SHOW_ALL = SHOW_BAUDRATE | SHOW_FORMAT | SHOW_FLOW | SHOW_TIMEOUT
|
|
|
|
|
|
class SerialConfigDialog(wx.Dialog):
|
|
"""\
|
|
Serial Port configuration dialog, to be used with pySerial 2.0+
|
|
When instantiating a class of this dialog, then the "serial" keyword
|
|
argument is mandatory. It is a reference to a serial.Serial instance.
|
|
the optional "show" keyword argument can be used to show/hide different
|
|
settings. The default is SHOW_ALL which corresponds to
|
|
SHOW_BAUDRATE|SHOW_FORMAT|SHOW_FLOW|SHOW_TIMEOUT. All constants can be
|
|
found in this module (not the class).
|
|
"""
|
|
|
|
def __init__(self, *args, **kwds):
|
|
# grab the serial keyword and remove it from the dict
|
|
self.serial = kwds['serial']
|
|
del kwds['serial']
|
|
self.show = SHOW_ALL
|
|
if 'show' in kwds:
|
|
self.show = kwds.pop('show')
|
|
# begin wxGlade: SerialConfigDialog.__init__
|
|
kwds["style"] = wx.DEFAULT_DIALOG_STYLE
|
|
wx.Dialog.__init__(self, *args, **kwds)
|
|
self.label_2 = wx.StaticText(self, -1, "Port")
|
|
self.choice_port = wx.Choice(self, -1, choices=[])
|
|
self.label_1 = wx.StaticText(self, -1, "Baudrate")
|
|
self.combo_box_baudrate = wx.ComboBox(self, -1, choices=[], style=wx.CB_DROPDOWN)
|
|
self.sizer_1_staticbox = wx.StaticBox(self, -1, "Basics")
|
|
self.panel_format = wx.Panel(self, -1)
|
|
self.label_3 = wx.StaticText(self.panel_format, -1, "Data Bits")
|
|
self.choice_databits = wx.Choice(self.panel_format, -1, choices=["choice 1"])
|
|
self.label_4 = wx.StaticText(self.panel_format, -1, "Stop Bits")
|
|
self.choice_stopbits = wx.Choice(self.panel_format, -1, choices=["choice 1"])
|
|
self.label_5 = wx.StaticText(self.panel_format, -1, "Parity")
|
|
self.choice_parity = wx.Choice(self.panel_format, -1, choices=["choice 1"])
|
|
self.sizer_format_staticbox = wx.StaticBox(self.panel_format, -1, "Data Format")
|
|
self.panel_timeout = wx.Panel(self, -1)
|
|
self.checkbox_timeout = wx.CheckBox(self.panel_timeout, -1, "Use Timeout")
|
|
self.text_ctrl_timeout = wx.TextCtrl(self.panel_timeout, -1, "")
|
|
self.label_6 = wx.StaticText(self.panel_timeout, -1, "seconds")
|
|
self.sizer_timeout_staticbox = wx.StaticBox(self.panel_timeout, -1, "Timeout")
|
|
self.panel_flow = wx.Panel(self, -1)
|
|
self.checkbox_rtscts = wx.CheckBox(self.panel_flow, -1, "RTS/CTS")
|
|
self.checkbox_xonxoff = wx.CheckBox(self.panel_flow, -1, "Xon/Xoff")
|
|
self.sizer_flow_staticbox = wx.StaticBox(self.panel_flow, -1, "Flow Control")
|
|
self.button_ok = wx.Button(self, wx.ID_OK, "")
|
|
self.button_cancel = wx.Button(self, wx.ID_CANCEL, "")
|
|
|
|
self.__set_properties()
|
|
self.__do_layout()
|
|
# end wxGlade
|
|
# attach the event handlers
|
|
self.__attach_events()
|
|
|
|
def __set_properties(self):
|
|
# begin wxGlade: SerialConfigDialog.__set_properties
|
|
self.SetTitle("Serial Port Configuration")
|
|
self.choice_databits.SetSelection(0)
|
|
self.choice_stopbits.SetSelection(0)
|
|
self.choice_parity.SetSelection(0)
|
|
self.text_ctrl_timeout.Enable(False)
|
|
self.button_ok.SetDefault()
|
|
# end wxGlade
|
|
self.SetTitle("Serial Port Configuration")
|
|
if self.show & SHOW_TIMEOUT:
|
|
self.text_ctrl_timeout.Enable(0)
|
|
self.button_ok.SetDefault()
|
|
|
|
if not self.show & SHOW_BAUDRATE:
|
|
self.label_1.Hide()
|
|
self.combo_box_baudrate.Hide()
|
|
if not self.show & SHOW_FORMAT:
|
|
self.panel_format.Hide()
|
|
if not self.show & SHOW_TIMEOUT:
|
|
self.panel_timeout.Hide()
|
|
if not self.show & SHOW_FLOW:
|
|
self.panel_flow.Hide()
|
|
|
|
# fill in ports and select current setting
|
|
preferred_index = 0
|
|
self.choice_port.Clear()
|
|
self.ports = []
|
|
for n, (portname, desc, hwid) in enumerate(sorted(serial.tools.list_ports.comports())):
|
|
self.choice_port.Append(u'{} - {}'.format(portname, desc))
|
|
self.ports.append(portname)
|
|
if self.serial.name == portname:
|
|
preferred_index = n
|
|
self.choice_port.SetSelection(preferred_index)
|
|
if self.show & SHOW_BAUDRATE:
|
|
preferred_index = None
|
|
# fill in baud rates and select current setting
|
|
self.combo_box_baudrate.Clear()
|
|
for n, baudrate in enumerate(self.serial.BAUDRATES):
|
|
self.combo_box_baudrate.Append(str(baudrate))
|
|
if self.serial.baudrate == baudrate:
|
|
preferred_index = n
|
|
if preferred_index is not None:
|
|
self.combo_box_baudrate.SetSelection(preferred_index)
|
|
else:
|
|
self.combo_box_baudrate.SetValue(u'{}'.format(self.serial.baudrate))
|
|
if self.show & SHOW_FORMAT:
|
|
# fill in data bits and select current setting
|
|
self.choice_databits.Clear()
|
|
for n, bytesize in enumerate(self.serial.BYTESIZES):
|
|
self.choice_databits.Append(str(bytesize))
|
|
if self.serial.bytesize == bytesize:
|
|
index = n
|
|
self.choice_databits.SetSelection(index)
|
|
# fill in stop bits and select current setting
|
|
self.choice_stopbits.Clear()
|
|
for n, stopbits in enumerate(self.serial.STOPBITS):
|
|
self.choice_stopbits.Append(str(stopbits))
|
|
if self.serial.stopbits == stopbits:
|
|
index = n
|
|
self.choice_stopbits.SetSelection(index)
|
|
# fill in parities and select current setting
|
|
self.choice_parity.Clear()
|
|
for n, parity in enumerate(self.serial.PARITIES):
|
|
self.choice_parity.Append(str(serial.PARITY_NAMES[parity]))
|
|
if self.serial.parity == parity:
|
|
index = n
|
|
self.choice_parity.SetSelection(index)
|
|
if self.show & SHOW_TIMEOUT:
|
|
# set the timeout mode and value
|
|
if self.serial.timeout is None:
|
|
self.checkbox_timeout.SetValue(False)
|
|
self.text_ctrl_timeout.Enable(False)
|
|
else:
|
|
self.checkbox_timeout.SetValue(True)
|
|
self.text_ctrl_timeout.Enable(True)
|
|
self.text_ctrl_timeout.SetValue(str(self.serial.timeout))
|
|
if self.show & SHOW_FLOW:
|
|
# set the rtscts mode
|
|
self.checkbox_rtscts.SetValue(self.serial.rtscts)
|
|
# set the rtscts mode
|
|
self.checkbox_xonxoff.SetValue(self.serial.xonxoff)
|
|
|
|
def __do_layout(self):
|
|
# begin wxGlade: SerialConfigDialog.__do_layout
|
|
sizer_2 = wx.BoxSizer(wx.VERTICAL)
|
|
sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
|
|
self.sizer_flow_staticbox.Lower()
|
|
sizer_flow = wx.StaticBoxSizer(self.sizer_flow_staticbox, wx.HORIZONTAL)
|
|
self.sizer_timeout_staticbox.Lower()
|
|
sizer_timeout = wx.StaticBoxSizer(self.sizer_timeout_staticbox, wx.HORIZONTAL)
|
|
self.sizer_format_staticbox.Lower()
|
|
sizer_format = wx.StaticBoxSizer(self.sizer_format_staticbox, wx.VERTICAL)
|
|
grid_sizer_1 = wx.FlexGridSizer(3, 2, 0, 0)
|
|
self.sizer_1_staticbox.Lower()
|
|
sizer_1 = wx.StaticBoxSizer(self.sizer_1_staticbox, wx.VERTICAL)
|
|
sizer_basics = wx.FlexGridSizer(3, 2, 0, 0)
|
|
sizer_basics.Add(self.label_2, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
sizer_basics.Add(self.choice_port, 0, wx.EXPAND, 0)
|
|
sizer_basics.Add(self.label_1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
sizer_basics.Add(self.combo_box_baudrate, 0, wx.EXPAND, 0)
|
|
sizer_basics.AddGrowableCol(1)
|
|
sizer_1.Add(sizer_basics, 0, wx.EXPAND, 0)
|
|
sizer_2.Add(sizer_1, 0, wx.EXPAND, 0)
|
|
grid_sizer_1.Add(self.label_3, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
grid_sizer_1.Add(self.choice_databits, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
|
|
grid_sizer_1.Add(self.label_4, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
grid_sizer_1.Add(self.choice_stopbits, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
|
|
grid_sizer_1.Add(self.label_5, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
grid_sizer_1.Add(self.choice_parity, 1, wx.EXPAND | wx.ALIGN_RIGHT, 0)
|
|
sizer_format.Add(grid_sizer_1, 1, wx.EXPAND, 0)
|
|
self.panel_format.SetSizer(sizer_format)
|
|
sizer_2.Add(self.panel_format, 0, wx.EXPAND, 0)
|
|
sizer_timeout.Add(self.checkbox_timeout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
sizer_timeout.Add(self.text_ctrl_timeout, 0, 0, 0)
|
|
sizer_timeout.Add(self.label_6, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
self.panel_timeout.SetSizer(sizer_timeout)
|
|
sizer_2.Add(self.panel_timeout, 0, wx.EXPAND, 0)
|
|
sizer_flow.Add(self.checkbox_rtscts, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
sizer_flow.Add(self.checkbox_xonxoff, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
|
|
sizer_flow.Add((10, 10), 1, wx.EXPAND, 0)
|
|
self.panel_flow.SetSizer(sizer_flow)
|
|
sizer_2.Add(self.panel_flow, 0, wx.EXPAND, 0)
|
|
sizer_3.Add(self.button_ok, 0, 0, 0)
|
|
sizer_3.Add(self.button_cancel, 0, 0, 0)
|
|
sizer_2.Add(sizer_3, 0, wx.ALL | wx.ALIGN_RIGHT, 4)
|
|
self.SetSizer(sizer_2)
|
|
sizer_2.Fit(self)
|
|
self.Layout()
|
|
# end wxGlade
|
|
|
|
def __attach_events(self):
|
|
self.button_ok.Bind(wx.EVT_BUTTON, self.OnOK)
|
|
self.button_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
|
|
if self.show & SHOW_TIMEOUT:
|
|
self.checkbox_timeout.Bind(wx.EVT_CHECKBOX, self.OnTimeout)
|
|
|
|
def OnOK(self, events):
|
|
success = True
|
|
self.serial.port = self.ports[self.choice_port.GetSelection()]
|
|
if self.show & SHOW_BAUDRATE:
|
|
try:
|
|
b = int(self.combo_box_baudrate.GetValue())
|
|
except ValueError:
|
|
with wx.MessageDialog(
|
|
self,
|
|
'Baudrate must be a numeric value',
|
|
'Value Error',
|
|
wx.OK | wx.ICON_ERROR) as dlg:
|
|
dlg.ShowModal()
|
|
success = False
|
|
else:
|
|
self.serial.baudrate = b
|
|
if self.show & SHOW_FORMAT:
|
|
self.serial.bytesize = self.serial.BYTESIZES[self.choice_databits.GetSelection()]
|
|
self.serial.stopbits = self.serial.STOPBITS[self.choice_stopbits.GetSelection()]
|
|
self.serial.parity = self.serial.PARITIES[self.choice_parity.GetSelection()]
|
|
if self.show & SHOW_FLOW:
|
|
self.serial.rtscts = self.checkbox_rtscts.GetValue()
|
|
self.serial.xonxoff = self.checkbox_xonxoff.GetValue()
|
|
if self.show & SHOW_TIMEOUT:
|
|
if self.checkbox_timeout.GetValue():
|
|
try:
|
|
self.serial.timeout = float(self.text_ctrl_timeout.GetValue())
|
|
except ValueError:
|
|
with wx.MessageDialog(
|
|
self,
|
|
'Timeout must be a numeric value',
|
|
'Value Error',
|
|
wx.OK | wx.ICON_ERROR) as dlg:
|
|
dlg.ShowModal()
|
|
success = False
|
|
else:
|
|
self.serial.timeout = None
|
|
if success:
|
|
self.EndModal(wx.ID_OK)
|
|
|
|
def OnCancel(self, events):
|
|
self.EndModal(wx.ID_CANCEL)
|
|
|
|
def OnTimeout(self, events):
|
|
if self.checkbox_timeout.GetValue():
|
|
self.text_ctrl_timeout.Enable(True)
|
|
else:
|
|
self.text_ctrl_timeout.Enable(False)
|
|
|
|
# end of class SerialConfigDialog
|
|
|
|
|
|
class MyApp(wx.App):
|
|
"""Test code"""
|
|
def OnInit(self):
|
|
wx.InitAllImageHandlers()
|
|
|
|
ser = serial.Serial()
|
|
print(ser)
|
|
# loop until cancel is pressed, old values are used as start for the next run
|
|
# show the different views, one after the other
|
|
# value are kept.
|
|
for flags in (SHOW_BAUDRATE, SHOW_FLOW, SHOW_FORMAT, SHOW_TIMEOUT, SHOW_ALL):
|
|
dialog_serial_cfg = SerialConfigDialog(None, -1, "", serial=ser, show=flags)
|
|
self.SetTopWindow(dialog_serial_cfg)
|
|
result = dialog_serial_cfg.ShowModal()
|
|
print(ser)
|
|
if result != wx.ID_OK:
|
|
break
|
|
# the user can play around with the values, CANCEL aborts the loop
|
|
while True:
|
|
dialog_serial_cfg = SerialConfigDialog(None, -1, "", serial=ser)
|
|
self.SetTopWindow(dialog_serial_cfg)
|
|
result = dialog_serial_cfg.ShowModal()
|
|
print(ser)
|
|
if result != wx.ID_OK:
|
|
break
|
|
return 0
|
|
|
|
# end of class MyApp
|
|
|
|
if __name__ == "__main__":
|
|
app = MyApp(0)
|
|
app.MainLoop()
|