示例#1
0
 def actualize_building(self, *kwargs):
     '''Actualize information about building
     '''
     bahn = Modbus.read_active_bahn()
     if Modbus.machine_is_building():
         self.status_label.text='Machine is building Bahn '+str(bahn)+' ...'
     else:
         self.status_label.text='Ready'
示例#2
0
 def run(self):
     modbus = Modbus.Modbus('paulharrison.hopto.org')
     while True:
         item = []
         try:
             # Order: [current, power, voltage]
             current_avg = modbus.read(3008,
                                       2)  # 3008 stores average current
             power_avg = modbus.read(3058, 2)  # 3058 stores average power
             voltage_avg = modbus.read(3024,
                                       2)  # 3024 stores average voltage
             total_energy = modbus.read(45098, 2)
             A = modbus.read(45118, 2)
             B = modbus.read(45120, 2)
             C = modbus.read(45122, 2)
             D = modbus.read(45124, 2)
             item.append(current_avg)
             item.append(power_avg)
             item.append(voltage_avg)
             item.append(total_energy)
             item.append(A)
             item.append(B)
             item.append(C)
             item.append(D)
             time.sleep(60)
         except struct.error:
             print('Struct Error exception', file=sys.stderr)
             time.sleep(2)
             os._exit(1)
         except ModbusException:
             print('Modbus I/O exception', file=sys.stderr)
             time.sleep(2)
             os._exit(1)
         self.q.put(item)
示例#3
0
def getBinder(port, echo=None):
    """Try to open Modbus(port) and determine Binder instrument
echo - open modbus with echo True/False; if None, try both
returns Binder instance or None in case of failure"""
    logger = logging.getLogger('getBinder')
    if echo is None:
        echos = (False, True)
    else:
        echos = (bool(echo), )

    b = None
    for echo in echos:
        try:
            m = Modbus(port, echo=echo)
            logger.info('Using serial %s with echo %s', repr(m.ser), echo)
        except (FileNotFoundError, ModbusError):
            logger.exception('Opening serial port failed')
            m.ser.close()
            return None
        for btype, bcls in BinderTypes.items():
            try:
                logger.debug('Trying chamber %s', btype)
                b = bcls(m)
                b.get_state()
            except ModbusError:
                logger.debug('failed')
                if b is not None:
                    b.__del__()
                    b = None
            else:
                logger.debug('chamber is %s', btype)
                return b
    return None
示例#4
0
                    required=True,
                    help='modbus port')
parser.add_argument('-u',
                    '--unit',
                    type=int,
                    required=True,
                    help='modbus unit')
parser.add_argument('-t',
                    '--type',
                    type=str,
                    required=True,
                    help='inverter type')

args = parser.parse_args()

wr = Modbus(args, logger=TableLogger())

if args.type == "tripower":
    add_tripower_register(wr)
elif args.type == "sbstorage":
    add_sbstorage_register(wr)
elif args.type == "sbxx-1av-41":
    add_sbxx_1av_41_register(wr)
else:
    sys.exit("Unknown inverter type.")

if args.list:
    wr.list_available_registers()
else:
    for register in args.registers:
        wr.poll_register(register)
示例#5
0
def KeyThread(modbus, scope):
    '''Thread to get command from console.'''
    global f

    key = input("Press Enter to continue...\n> ")
    f.close()
    print("bye-bye")
    os.kill(os.getpid(), signal.SIGINT)


if __name__ == '__main__':
    global data
    global f
    global ReadingADC

    modbus = Modbus("/dev/ttyUSB0", 115200, 5)
    scope = Scope()
    data = [[] for i in range(modbus.GetNumChannels())]
    rt = threading.Thread(target=ReadThread, args=(modbus, scope, 0.01))
    wt = threading.Thread(target=WriteThread, args=(scope, ))
    kt = threading.Thread(target=KeyThread, args=(
        modbus,
        scope,
    ))
    filename = "data-" + time.strftime("%Y%m%d%H%M%S") + ".txt"
    f = open(filename, "w")

    # Bind data to scope.
    scope.data = data
    # Send start sample command to oscilloscope.
    modbus.StartSample()
示例#6
0
 def build(self, bahn):
     '''Start building
     '''
     if not self.building:
         #Check which
         if bahn==0:
             print "Lager"
             Modbus.transfer_bahn_nr(nr=0)
         elif bahn==1:
             print "Bahn1"
             Modbus.transfer_bahn_nr(nr=1)
         elif bahn==2:
             print "Bahn2"
             Modbus.transfer_bahn_nr(nr=2)
         elif bahn==3:
             print "Bahn3"
             Modbus.transfer_bahn_nr(nr=3)
         elif bahn==4:
             print "Bahn4"
             Modbus.transfer_bahn_nr(nr=4)
         elif bahn==10:
             print "BahnPC"
             Modbus.transfer_bahn_nr(nr=10)
         else:
             print "No suitable Bahn found"
         
     return
示例#7
0
 def reset_safety(self):
     '''Reset safety on machine
     '''
     Modbus.reset_safety(callback=self.success)
示例#8
0
 def move_array(self):
     '''Move the array with all the cubes to the SPS
     '''
     anlage_ = depot.calculate_mazine(depot.depot, depot.demo_anlage)
     Modbus.transfer_array(array=anlage_, callback=self.success)
示例#9
0

if __name__ == '__main__':

    # Pipes to Webapp
    SERIAL_CHILD, SERIAL_PARENT = Pipe()

    # Pipes for encoder
    ENCODER_CHILD, ENCODER_PARENT = Pipe()

    # Queues for sql database connector
    RECORD_QUEUE = Queue()
    DATA_QUEUE = Queue()

    # Start AquaTROLL
    TROLL = Modbus(DATA_QUEUE)

    # Starts camera
    CAMERA_PROCESS = Process(target=Camera.start_camera,
                             args=((2592, 1944), 300, "Images", RECORD_QUEUE))
    CAMERA_PROCESS.start()

    # Starts sql database connector that handles writing and reading(broadcasts to socket)
    DATABASE_CONNECTOR = Process(target=sqlConnector.start_sqlConnector,\
    args=(RECORD_QUEUE,DATA_QUEUE))

    # DATABASE_CONNECTOR = Process(target=sqlConnector.start_sqlConnector,\
    #     args=(RECORD_QUEUE,DATA_QUEUE, ENCODER_PARENT))
    DATABASE_CONNECTOR.start()

    # Starts thread that runs serial communication.
示例#10
0
    parser.add_argument("serialPort", help="The serial port device to use")
    parser.add_argument("--httpListenPort", help="The port for the HTTP server to listen on", type=int, default=8080)
    parser.add_argument("--verbose", help="Use verbose logging", action="store_true")
    args = parser.parse_args()

    logging.basicConfig()
    log = logging.getLogger()
    if args.verbose:
        log.setLevel(logging.DEBUG)
    else:
        log.setLevel(logging.INFO)

    log.info("Listening on port {}, using device {}".format(args.httpListenPort, args.serialPort))

    loop, client = AsyncModbusSerialClient(schedulers.ASYNC_IO, port=args.serialPort, baudrate=19200, method="rtu")
    modbus = Modbus(client.protocol)
    handler = HttpHandler(modbus)
    app = web.Application()
    app.add_routes([
        web.get("/", handler.handle_root),
        web.get("/summary", handler.get_summary),
        web.get("/mode/{flag}", handler.get_mode_status),
        web.post("/mode/{flag}", handler.set_mode_status),
        web.post("/setSetting/{setting}/{value}", handler.set_setting)
    ])

    try:
        loop.run_until_complete(web._run_app(app, port=args.httpListenPort))
    finally:
        loop.close()
示例#11
0
def add_tripower_register(wr: Modbus):
    wr.add_register(U32(30051, "Nameplate.MainModel", "Geräteklasse"))
    wr.add_register(U32(30053, "Nameplate.Model", "Gerätetyp"))
    wr.add_register(U32(30055, "Nameplate.Vendor", "Hersteller"))
    wr.add_register(U32(30057, "Nameplate.SerNum", "Seriennummer"))
    wr.add_register(U32(30059, "Nameplate.PkgRev", "Softwarepaket"))
    wr.add_register(U32(30199, "Operation.RmgTms",
                        "Wartezeit bis Einspeisung"))
    wr.add_register(U32(30201, "Operation.Health", "Zustand"))
    wr.add_register(
        U32(30203, "Operation.HealthStt.Ok", "Nennleistung im Zustand Ok"))
    wr.add_register(
        U32(30205, "Operation.HealthStt.Wrn",
            "Nennleistung im Zustand Warnung"))
    wr.add_register(
        U32(30207, "Operation.HealthStt.Alm",
            "Nennleistung im Zustand Fehler"))
    wr.add_register(U32(30211, "Operation.Evt.Prio", "Empfohlene Aktion"))
    wr.add_register(U32(30213, "Operation.Evt.Msg", "Meldung"))
    wr.add_register(U32(30215, "Operation.Evt.Dsc", "Fehlerbehebungsmaßnahme"))
    wr.add_register(U32(30217, "Operation.GriSwStt", "Netzrelais/-schütz"))
    wr.add_register(U32(30219, "Operation.DrtStt", "Leistungsreduzierung"))
    wr.add_register(U32(30225, "Isolation.LeakRis", "Isolationswiderstand"))
    wr.add_register(U32(30231, "Inverter.WLim", "Maximale Gerätewirkleistung"))
    wr.add_register(
        U32(30233, "Inverter.WMax", "Eingestellte Wirkleistungsgrenze"))
    wr.add_register(
        U32(30247, "Operation.Evt.EvtNo",
            "Aktuelle Ereignisnummer für Hersteller"))
    wr.add_register(U64(30513, "Metering.TotWhOut", "Gesamtertrag"))
    wr.add_register(U64(30521, "Metering.TotOpTms", "Betriebszeit"))
    wr.add_register(U64(30525, "Metering.TotFeedTms", "Einspeisezeit"))
    wr.add_register(U32(30529, "Metering.TotWhOut", "Gesamtertrag Wh"))
    wr.add_register(U32(30531, "Metering.TotWhOut", "Gesamtertrag kWh"))
    wr.add_register(U32(30533, "Metering.TotWhOut", "Gesamtertrag MWh"))
    wr.add_register(U32(30541, "Metering.TotOpTms", "Betriebszeit"))
    wr.add_register(U32(30543, "Metering.TotFeedTms", "Einspeisezeit"))
    wr.add_register(
        U32(30559, "Operation.EvtCntUsr", "Anzahl Ereignisse für Benutzer"))
    wr.add_register(
        U32(30561, "Operation.EvtCntIstl",
            "Anzahl Ereignisse für Installateur"))
    wr.add_register(
        U32(30563, "Operation.EvtCntSvc", "Anzahl Ereignisse für Service"))
    wr.add_register(
        U32(30581, "Metering.GridMs.TotWhIn", "Zählerstand Bezugszähler"))
    wr.add_register(
        U32(30583, "Metering.GridMs.TotWhOut", "Zählerstand Einspeisezähler"))
    wr.add_register(
        U32(30599, "Operation.GriSwCnt", "Anzahl Netzzuschaltungen"))
    wr.add_register(S32(30769, "DcMs.Amp", "DC Strom Eingang"))
    wr.add_register(S32(30771, "DcMs.Vol", "DC Spannung Eingang"))
    wr.add_register(S32(30773, "DcMs.Watt", "DC Leistung Eingang"))
    wr.add_register(S32(30775, "GridMs.TotW", "Leistung"))
    wr.add_register(S32(30777, "GridMs.W.phsA", "Leistung L1"))
    wr.add_register(S32(30779, "GridMs.W.phsB", "Leistung L2"))
    wr.add_register(S32(30781, "GridMs.W.phsC", "Leistung L3"))
    wr.add_register(U32(30783, "GridMs.PhV.phsA", "Netzspannung Phase L1"))
    wr.add_register(U32(30785, "GridMs.PhV.phsB", "Netzspannung Phase L2"))
    wr.add_register(U32(30787, "GridMs.PhV.phsC", "Netzspannung Phase L3"))
    wr.add_register(
        U32(30789, "GridMs.PhV.phsA2B", "Netzspannung Phase L1 gegen L2"))
    wr.add_register(
        U32(30791, "GridMs.PhV.phsB2C", "Netzspannung Phase L2 gegen L3"))
    wr.add_register(
        U32(30793, "GridMs.PhV.phsC2A", "Netzspannung Phase L3 gegen L1"))
    wr.add_register(U32(30795, "GridMs.TotA", "Netzstrom"))
    wr.add_register(U32(30803, "GridMs.Hz", "Netzfrequenz"))
    wr.add_register(S32(30805, "GridMs.TotVAr", "Blindleistung"))
    wr.add_register(S32(30807, "GridMs.VAr.phsA", "Blindleistung L1"))
    wr.add_register(S32(30809, "GridMs.VAr.phsB", "Blindleistung L2"))
    wr.add_register(S32(30811, "GridMs.VAr.phsC", "Blindleistung L3"))
    wr.add_register(S32(30813, "GridMs.TotVA", "Scheinleistung"))
    wr.add_register(S32(30815, "GridMs.VA.phsA", "Scheinleistung L1"))
    wr.add_register(S32(30817, "GridMs.VA.phsB", "Scheinleistung L2"))
    wr.add_register(S32(30819, "GridMs.VA.phsC", "Scheinleistung L3"))
    wr.add_register(
        U32(
            30825, "Inverter.VArModCfg.VArMod",
            "Betriebsart der statischen Spannungshaltung, Konfiguration der statischen Spannungshaltung"
        ))
    wr.add_register(
        S32(30829, "Inverter.VArModCfg.VArCnstCfg.VArNom",
            "Blindleistungssollwert in %"))
    wr.add_register(
        S32(
            30831, "Inverter.VArModCfg.PFCnstCfg.PF",
            "Sollwert des cos Phi, Konfiguration des cos Phi, direkte Vorgabe")
    )
    wr.add_register(
        U32(
            30833, "Inverter.VArModCfg.PFCnstCfg.PFExt",
            "Erregungsart des cos Phi, Konfiguration des cos Phi, direkte Vorgabe"
        ))
    wr.add_register(
        U32(30835, "Inverter.WModCfg.WMod",
            "Betriebsart des Einspeisemanagements"))
    wr.add_register(
        U32(30837, "Inverter.WModCfg.WCnstCfg.W",
            "Wirkleistungsbegrenzung in W"))
    wr.add_register(
        U32(30839, "Inverter.WModCfg.WCnstCfg.WNom",
            "Wirkleistungsbegrenzung in %"))
    wr.add_register(S32(30865, "Metering.GridMs.TotWIn", "Leistung Bezug"))
    wr.add_register(
        S32(30867, "Metering.GridMs.TotWOut", "Leistung Einspeisung"))
    wr.add_register(
        U32(30875, "MltFncSw.Stt", "Status des Multifunktionsrelais"))
    wr.add_register(
        U32(30881, "Operation.PvGriConn", "Netzanbindung der Anlage"))
    wr.add_register(
        U32(30925, "Spdwr.ComSocA.ConnSpd",
            "Verbindungsgeschwindigkeit von SMACOM A"))
    wr.add_register(
        U32(30927, "Spdwr.ComSocA.DpxMode", "Duplexmodus von SMACOM A"))
    wr.add_register(
        U32(30929, "Spdwr.ComSocA.Stt",
            "Speedwire-Verbindungsstatus von SMACOM A"))
    wr.add_register(
        U32(30931, "Spdwr.ComSocB.ConnSpd",
            "Verbindungsgeschwindigkeit von SMACOM B"))
    wr.add_register(
        U32(30933, "Spdwr.ComSocB.DpxMode", "Duplexmodus von SMACOM B"))
    wr.add_register(
        U32(30935, "Spdwr.ComSocB.Stt",
            "Speedwire-Verbindungsstatus von SMACOM B"))
    wr.add_register(U32(30949, "GridMs.TotPFPrc", "Verschiebungsfaktor"))
    wr.add_register(S32(30953, "Coolsys.Cab.TmpVal", "Innentemperatur"))
    wr.add_register(S32(30957, "DcMs.Amp", "DC Strom Eingang"))
    wr.add_register(S32(30959, "DcMs.Vol", "DC Spannung Eingang"))
    wr.add_register(S32(30961, "DcMs.Watt", "DC Leistung Eingang"))
    wr.add_register(S32(30975, "Inverter.DclVol", "Zwischenkreisspannung"))
    wr.add_register(S32(30977, "GridMs.A.phsA", "Netzstrom Phase L1"))
    wr.add_register(S32(30979, "GridMs.A.phsB", "Netzstrom Phase L2"))
    wr.add_register(S32(30981, "GridMs.A.phsC", "Netzstrom Phase L3"))
    wr.add_register(STR32(31017, "Spdwr.ActlIp", "-"))
    wr.add_register(STR32(31025, "Spdwr.ActlSnetMsk", "-"))
    wr.add_register(STR32(31033, "Spdwr.ActlGwIp", "-"))
    wr.add_register(STR32(31041, "Spdwr.ActlDnsSrvIp", "-"))
    wr.add_register(
        U32(31061, "Bat.ChaCtlComAval",
            "Steuerung der Batterieladung über Kommunikation verfügbar"))
    wr.add_register(
        U32(31085, "Operation.HealthStt.Ok", "Nennleistung im Zustand Ok"))
    wr.add_register(
        S32(31159, "Operation.Dmd.VArCtl", "Aktuelle Vorgabe Blindleistung Q"))
    wr.add_register(S32(31221, "GridMs.TotPFEEI", "EEI-Verschiebungsfaktor"))
    wr.add_register(S32(31247, "Isolation.FltA", "Fehlerstrom"))
    wr.add_register(
        U32(31253, "Metering.GridMs.PhV.phsA", "Netzspannung Phase L1"))
    wr.add_register(
        U32(31255, "Metering.GridMs.PhV.phsB", "Netzspannung Phase L2"))
    wr.add_register(
        U32(31257, "Metering.GridMs.PhV.phsC", "Netzspannung Phase L3"))
    wr.add_register(
        U32(31259, "Metering.GridMs.W.phsA", "Leistung Netzeinspeisung L1"))
    wr.add_register(
        U32(31261, "Metering.GridMs.W.phsB", "Leistung Netzeinspeisung L2"))
    wr.add_register(
        U32(31263, "Metering.GridMs.W.phsC", "Leistung Netzeinspeisung L3"))
    wr.add_register(
        U32(31265, "Metering.GridMs.WIn.phsA", "Leistung Netzbezug Phase L1"))
    wr.add_register(
        U32(31267, "Metering.GridMs.WIn.phsB", "Leistung Netzbezug Phase L2"))
    wr.add_register(
        U32(31269, "Metering.GridMs.WIn.phsC", "Leistung Netzbezug Phase L3"))
    wr.add_register(
        S32(31271, "Metering.GridMs.VAr.phsA",
            "Blindleistung Netzeinspeisung Phase L1"))
    wr.add_register(
        S32(31273, "Metering.GridMs.VAr.phsB",
            "Blindleistung Netzeinspeisung Phase L2"))
    wr.add_register(
        S32(31275, "Metering.GridMs.VAr.phsC",
            "Blindleistung Netzeinspeisung Phase L3"))
    wr.add_register(
        S32(31277, "Metering.GridMs.TotVAr", "Blindleistung Netzeinspeisung"))
    wr.add_register(
        U32(31405, "Operation.Dmd.WCtl",
            "Aktuelle Vorgabe Wirkleistungsbegrenzung P"))
    wr.add_register(
        U32(31407, "Operation.Dmd.PFCtl", "Aktuelle Vorgabe cos Phi"))
    wr.add_register(
        U32(31409, "Operation.Dmd.PFExtCtl",
            "Aktuelle Vorgabe Erregungsart cos Phi"))
    wr.add_register(
        S32(31411, "Operation.Dmd.VArCtl", "Aktuelle Vorgabe Blindleistung Q"))
    wr.add_register(S32(31793, "DcMs.Amp", "DC Strom Eingang"))
    wr.add_register(S32(31795, "DcMs.Amp", "DC Strom Eingang"))
    wr.add_register(S32(34113, "Coolsys.Cab.TmpVal", "Innentemperatur"))
    wr.add_register(S32(34609, "Env.TmpVal", "Außentemperatur"))
    wr.add_register(
        S32(34611, "Env.TmpValMax", "Höchste gemessene Außentemperatur"))
    wr.add_register(U32(34615, "Env.HorWSpd", "Windgeschwindigkeit"))
    wr.add_register(S32(34621, "Mdul.TmpVal", "Modultemperatur"))
    wr.add_register(
        U32(34623, "Env.ExInsol", "Einstrahlung auf externen Sensor"))
    wr.add_register(S32(34625, "Env.TmpVal", "Außentemperatur"))
    wr.add_register(S32(34627, "Env.TmpVal", "Außentemperatur"))
    wr.add_register(S32(34629, "Mdul.TmpVal", "Modultemperatur"))
    wr.add_register(S32(34631, "Mdul.TmpVal", "Modultemperatur"))
    wr.add_register(U32(34633, "Env.HorWSpd", "Windgeschwindigkeit"))
    wr.add_register(U32(34635, "Env.HorWSpd", "Windgeschwindigkeit"))
    wr.add_register(
        U32(34669, "Bat.ChaCtlComAval",
            "Steuerung der Batterieladung über Kommunikation verfügbar"))
    wr.add_register(
        U64(35377, "Operation.EvtCntUsr", "Anzahl Ereignisse für Benutzer"))
    wr.add_register(
        U64(35381, "Operation.EvtCntIstl",
            "Anzahl Ereignisse für Installateur"))
    wr.add_register(
        U64(35385, "Operation.EvtCntSvc", "Anzahl Ereignisse für Service"))
    wr.add_register(U32(40003, "DtTm.TmZn", "Zeitzone"))
    wr.add_register(
        U32(40005, "DtTm.DlSvIsOn",
            "Automatische Sommer-/Winterzeitumstellung eingeschaltet"))
    wr.add_register(U32(40009, "Operation.OpMod", "Betriebszustand"))
    wr.add_register(U32(40013, "CntrySettings.Lang", "Sprache der Oberfläche"))
    wr.add_register(
        S16(40015, "Inverter.VArModCfg.VArCtlComCfg.VArNom",
            "Normierte Blindleistungsvorgabe durch Anlagensteuerung"))
    wr.add_register(
        S16(40016, "Inverter.WModCfg.WCtlComCfg.WNom",
            "Normierte Wirkleistungsbegrenzung durch Anlagensteuerung"))
    wr.add_register(U32(40018, "Inverter.FstStop", "Schnellabschaltung"))
    wr.add_register(
        S16(40022, "Inverter.VArModCfg.VArCtlComCfg.VArNomPrc",
            "Normierte Blindleistungsbegrenzung durch Anlagensteuerung"))
    wr.add_register(
        S16(40023, "Inverter.WModCfg.WCtlComCfg.WNomPrc",
            "Normierte Wirkleistungsbegrenzung durch Anlagensteuerung"))
    wr.add_register(
        U16(40024, "Inverter.VArModCfg.PFCtlComCfg.PF",
            "Verschiebungsfaktor durch Anlagensteuerung"))
    wr.add_register(
        U32(40025, "Inverter.VArModCfg.PFCtlComCfg.PFExt",
            "Erregungsart durch Anlagensteuerung"))
    wr.add_register(U32(40029, "Operation.OpStt", "Betriebsstatus"))
    wr.add_register(
        U32(40063, "Nameplate.CmpMain.SwRev",
            "Firmware-Version des Hauptprozessors"))
    wr.add_register(U32(40067, "Nameplate.SerNum", "Seriennummer"))
    wr.add_register(U32(40077, "Sys.DevRstr", "Geräteneustart auslösen"))
    wr.add_register(
        U32(40095, "GridGuard.Cntry.VolCtl.Max",
            "Spannungsüberwachung obere Maximalschwelle"))
    wr.add_register(U32(40109, "GridGuard.Cntry", "Eingestellte Ländernorm"))
    wr.add_register(U32(40133, "GridGuard.Cntry.VRtg", "Netz-Nennspannung"))
    wr.add_register(U32(40135, "GridGuard.Cntry.HzRtg", "Nennfrequenz"))
    wr.add_register(
        S32(40149, "Inverter.WModCfg.WCtlComCfg.WSpt", "Wirkleistungsvorgabe"))
    wr.add_register(
        U32(40151, "Inverter.WModCfg.WCtlComCfg.WCtlComAct",
            "Wirk- und Blindleistungsregelung über Kommunikation"))
    wr.add_register(
        U32(40157, "Spdwr.AutoCfgIsOn",
            "Automatische Speedwire-Konfiguration eingeschaltet"))
    wr.add_register(STR32(40159, "Spdwr.Ip", "-"))
    wr.add_register(STR32(40167, "Spdwr.SnetMsk", "-"))
    wr.add_register(STR32(40175, "Spdwr.GwIp", "-"))
    wr.add_register(
        U32(40185, "Inverter.VALim", "Maximale Gerätescheinleistung"))
    wr.add_register(
        U32(40195, "Inverter.VAMax", "Eingestellte Scheinleistungsgrenze"))
    wr.add_register(
        U32(
            40200, "Inverter.VArModCfg.VArMod",
            "Betriebsart der statischen Spannungshaltung, Konfiguration der statischen Spannungshaltung"
        ))
    wr.add_register(
        S32(40204, "Inverter.VArModCfg.VArCnstCfg.VArNom",
            "Blindleistungssollwert in %"))
    wr.add_register(
        S32(
            40206, "Inverter.VArModCfg.PFCnstCfg.PF",
            "Sollwert des cos Phi, Konfiguration des cos Phi, direkte Vorgabe")
    )
    wr.add_register(
        U32(
            40208, "Inverter.VArModCfg.PFCnstCfg.PFExt",
            "Erregungsart des cos Phi, Konfiguration des cos Phi, direkte Vorgabe"
        ))
    wr.add_register(
        U32(40210, "Inverter.WModCfg.WMod",
            "Betriebsart des Einspeisemanagements"))
    wr.add_register(
        U32(40212, "Inverter.WModCfg.WCnstCfg.W",
            "Wirkleistungsbegrenzung in W"))
    wr.add_register(
        U32(40214, "Inverter.WModCfg.WCnstCfg.WNom",
            "Wirkleistungsbegrenzung in %"))
    wr.add_register(
        U32(40216, "Inverter.WCtlHzModCfg.WCtlHzMod",
            "Betriebsart der Wirkleistungsreduktion bei Überfrequenz P(f)"))
    wr.add_register(
        U32(
            40218, "Inverter.WCtlHzModCfg.WCtlHzCfg.HzStr",
            "Abstand der Startfrequenz zur Netzfrequenz, Konfiguration des linearen Gradienten der Momentanleistung"
        ))
    wr.add_register(
        U32(
            40220, "Inverter.WCtlHzModCfg.WCtlHzCfg.HzStop",
            "Abstand der Rücksetzfrequenz zur Netzfrequenz, Konfiguration des linearen Gradienten der Momentanleistung"
        ))
    wr.add_register(
        U32(
            40222, "Inverter.VArModCfg.PFCtlWCfg.PFStr",
            "cos Phi des Startpunktes, Konfiguration der cos Phi(P)-Kennlinie")
    )
    wr.add_register(
        U32(
            40224, "Inverter.VArModCfg.PFCtlWCfg.PFExtStr",
            "Erregungsart des Startpunktes, Konfiguration der cos Phi(P)-Kennlinie"
        ))
    wr.add_register(
        U32(40226, "Inverter.VArModCfg.PFCtlWCfg.PFStop",
            "cos Phi des Endpunktes, Konfiguration der cos Phi(P)-Kennlinie"))
    wr.add_register(
        U32(
            40228, "Inverter.VArModCfg.PFCtlWCfg.PFExtStop",
            "Erregungsart des Endpunktes, Konfiguration der cos Phi(P)-Kennlinie"
        ))
    wr.add_register(
        U32(
            40230, "Inverter.VArModCfg.PFCtlWCfg.WNomStr",
            "Wirkleistung des Startpunktes, Konfiguration der cos Phi(P)-Kennlinie"
        ))
    wr.add_register(
        U32(
            40232, "Inverter.VArModCfg.PFCtlWCfg.WNomStop",
            "Wirkleistung des Endpunktes, Konfiguration der cos Phi(P)-Kennlinie"
        ))
    wr.add_register(U32(40234, "Inverter.WGra", "Wirkleistungsgradient"))
    wr.add_register(
        U32(
            40238, "Inverter.WCtlHzModCfg.WCtlHzCfg.WGra",
            "Wirkleistungsgradient, Konfiguration des linearen Gradienten der Momentanleistung"
        ))
    wr.add_register(
        U32(
            40240, "Inverter.WCtlHzModCfg.WCtlHzCfg.HystEna",
            "Aktivierung der Schleppzeigerfunktion, Konfiguration des linearen Gradienten der Momentanleistung"
        ))
    wr.add_register(
        U32(
            40242, "Inverter.WCtlHzModCfg.WCtlHzCfg.HzStopWGra",
            "Wirkleistungsgradient nach Rücksetzfrequenz, Konfiguration des linearen Gradienten der Momentanleistung"
        ))
    wr.add_register(
        U32(
            40244, "Inverter.DGSModCfg.DGSFlCfg.ArGraMod",
            "Blindstromstatik, Konfiguration der vollständigen dynamischen Netzstützung"
        ))
    wr.add_register(
        U32(
            40246, "Inverter.DGSModCfg.DGSFlCfg.ArGraSag",
            "Gradient K der Blindstromstatik für Unterpannung bei dynamischer Netzstützung"
        ))
    wr.add_register(
        U32(
            40248, "Inverter.DGSModCfg.DGSFlCfg.ArGraSwell",
            "Gradient K der Blindstromstatik für Überpannung bei dynamischer Netzstützung"
        ))
    wr.add_register(
        U32(
            40250, "Inverter.DGSModCfg.DGSMod",
            "Betriebsart der dynamischen Netzstützung, Konfiguration der dynamischen Netzstützung"
        ))
    wr.add_register(
        S32(
            40252, "Inverter.DGSModCfg.DGSFlCfg.DbVolNomMin",
            "Untergrenze Spannungstotband, Konfiguration der vollständigen dynamischen Netzstützung"
        ))
    wr.add_register(
        U32(
            40254, "Inverter.DGSModCfg.DGSFlCfg.DbVolNomMax",
            "Obergrenze Spannungstotband, Konfiguration der vollständigen dynamischen Netzstützung"
        ))
    wr.add_register(
        U32(40256, "Inverter.DGSModCfg.PwrCirInopVolNom",
            "PWM-Sperrspannung, Konfiguration der dynamischen Netzstützung"))
    wr.add_register(
        U32(
            40258, "Inverter.DGSModCfg.PwrCirInopTms",
            "PWM-Sperrverzögerung, Konfiguration der dynamischen Netzstützung")
    )
    wr.add_register(
        U32(40262, "Inverter.UtilCrvCfg.Crv0.NumPt",
            "Kennlinie, Anzahl der zu verwendenden Punkte der Kennlinie"))
    wr.add_register(
        U32(40264, "Inverter.UtilCrvCfg.Crv0.NumPt",
            "Kennlinie, Anzahl der zu verwendenden Punkte der Kennlinie"))
    wr.add_register(
        U32(40266, "Inverter.UtilCrvCfg.Crv0.NumPt",
            "Kennlinie, Anzahl der zu verwendenden Punkte der Kennlinie"))
    wr.add_register(
        S32(40282, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40284, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40286, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40288, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40290, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40292, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40294, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40296, "Inverter.UtilCrvCfg.CrvPt1.XVal",
            "X-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40306, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40308, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40310, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40312, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40314, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40316, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40318, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40320, "Inverter.UtilCrvCfg.CrvPt1.YVal",
            "Y-Werte der Kennlinie 1"))
    wr.add_register(
        S32(40330, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40332, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40334, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40336, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40338, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40340, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40342, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40344, "Inverter.UtilCrvCfg.CrvPt2.XVal",
            "X-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40354, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40356, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40358, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40360, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40362, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40364, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40366, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40368, "Inverter.UtilCrvCfg.CrvPt2.YVal",
            "Y-Werte der Kennlinie 2"))
    wr.add_register(
        S32(40378, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40380, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40382, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40384, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40386, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40388, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40390, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40392, "Inverter.UtilCrvCfg.CrvPt3.XVal",
            "X-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40402, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40404, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40406, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40408, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40410, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40412, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40414, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        S32(40416, "Inverter.UtilCrvCfg.CrvPt3.YVal",
            "Y-Werte der Kennlinie 3"))
    wr.add_register(
        U32(40428, "GridGuard.Cntry.FrqCtl.hhLim",
            "Frequenzüberwachung mittlere Maximalschwelle"))
    wr.add_register(
        U32(40430, "GridGuard.Cntry.FrqCtl.hhLimTmms",
            "Frequenzüberwachung mittlere Maximalschwelle Auslösezeit"))
    wr.add_register(
        U32(40432, "GridGuard.Cntry.FrqCtl.hLim",
            "Frequenzüberwachung untere Maximalschwelle"))
    wr.add_register(
        U32(40434, "GridGuard.Cntry.FrqCtl.hLimTmms",
            "Frequenzüberwachung untere Maximalschwelle Auslösezeit"))
    wr.add_register(
        U32(40436, "GridGuard.Cntry.FrqCtl.lLim",
            "Frequenzüberwachung obere Minimalschwelle"))
    wr.add_register(
        U32(40438, "GridGuard.Cntry.FrqCtl.lLimTmms",
            "Frequenzüberwachung obere Minimalschwelle Auslösezeit"))
    wr.add_register(
        U32(40440, "GridGuard.Cntry.FrqCtl.llLim",
            "Frequenzüberwachung mittlere Minimalschwelle"))
    wr.add_register(
        U32(40442, "GridGuard.Cntry.FrqCtl.llLimTmms",
            "Frequenzüberwachung mittlere Minimalschwelle Auslösezeit"))
    wr.add_register(
        U32(40446, "GridGuard.Cntry.VolCtl.MaxTmms",
            "Spannungsüberwachung obere Maximalschwelle Auslösezeit"))
    wr.add_register(
        U32(40448, "GridGuard.Cntry.VolCtl.hhLim",
            "Spannungsüberwachung mittlere Maximalschwelle"))
    wr.add_register(
        U32(40450, "GridGuard.Cntry.VolCtl.hhLimTmms",
            "Spannungsüberwachung mittlere Maximalschwelle Auslösezeit"))
    wr.add_register(
        U32(40452, "GridGuard.Cntry.VolCtl.hLim",
            "Spannungsüberwachung untere Maximalschwelle"))
    wr.add_register(
        U32(40456, "GridGuard.Cntry.VolCtl.hLimTmms",
            "Spannungsüberwachung untere Maximalschwelle Auslösezeit"))
    wr.add_register(
        U32(40458, "GridGuard.Cntry.VolCtl.lLim",
            "Spannungsüberwachung obere Minimalschwelle"))
    wr.add_register(
        U32(40462, "GridGuard.Cntry.VolCtl.lLimTmms",
            "Spannungsüberwachung obere Minimalschwelle Auslösezeit"))
    wr.add_register(
        U32(40464, "GridGuard.Cntry.VolCtl.llLim",
            "Spannungsüberwachung mittlere Minimalschwelle"))
    wr.add_register(
        U32(40466, "GridGuard.Cntry.VolCtl.llLimTmms",
            "Spannungsüberwachung mittlere Minimalschwelle Auslösezeit"))
    wr.add_register(U32(40472, "Inverter.PlntCtl.VRef", "Referenzspannung"))
    wr.add_register(
        S32(40474, "Inverter.PlntCtl.VRefOfs", "Referenzkorrekturspannung"))
    wr.add_register(U32(40480, "Nameplate.ARtg", "Nennstrom über alle Phasen"))
    wr.add_register(U32(40482, "Inverter.VArGra", "Blindleistungsgradient"))
    wr.add_register(
        U32(40484, "Inverter.WGraEna",
            "Aktivierung des Wirkleistungsgradienten"))
    wr.add_register(
        U32(
            40490, "Inverter.VArModCfg.VArCtlVolCfg.VArGraNom",
            "Blindleistungsgradient, Konfiguration der Blindleistungs-/Spannungskennlinie Q(U)"
        ))
    wr.add_register(STR32(40497, "Nameplate.MacId", "-"))
    wr.add_register(STR32(40513, "Spdwr.DnsSrvIp", "-"))
    wr.add_register(
        U32(40575, "MltFncSw.OpMode", "Betriebsart des Multifunktionsrelais"))
    wr.add_register(
        U32(40577, "MltFncSw.OpMode", "Betriebsart des Multifunktionsrelais"))
    wr.add_register(STR32(40631, "Nameplate.Location", "-"))
    wr.add_register(
        U32(40647, "Upd.AutoUpdIsOn", "Automatische Updates eingeschaltet"))
    wr.add_register(U32(40789, "Nameplate.ComRev", "Kommunikationsversion"))
    wr.add_register(
        U32(40791, "Inverter.PlntCtl.IntvTmsMax",
            "Timeout für Kommunikationsfehlermeldung"))
    wr.add_register(
        U32(
            40855, "Inverter.UtilCrvCfg.Crv0.RmpDec",
            "Kennlinie, Absenkungsrampe für Erreichung des Kennlinienarbeitspunktes"
        ))
    wr.add_register(
        U32(
            40857, "Inverter.UtilCrvCfg.Crv0.RmpDec",
            "Kennlinie, Absenkungsrampe für Erreichung des Kennlinienarbeitspunktes"
        ))
    wr.add_register(
        U32(
            40859, "Inverter.UtilCrvCfg.Crv0.RmpDec",
            "Kennlinie, Absenkungsrampe für Erreichung des Kennlinienarbeitspunktes"
        ))
    wr.add_register(
        U32(
            40875, "Inverter.UtilCrvCfg.Crv0.RmpInc",
            "Kennlinie, Steigerungsrampe für Erreichung des Kennlinienarbeitspunktes"
        ))
    wr.add_register(
        U32(
            40877, "Inverter.UtilCrvCfg.Crv0.RmpInc",
            "Kennlinie, Steigerungsrampe für Erreichung des Kennlinienarbeitspunktes"
        ))
    wr.add_register(
        U32(
            40879, "Inverter.UtilCrvCfg.Crv0.RmpInc",
            "Kennlinie, Steigerungsrampe für Erreichung des Kennlinienarbeitspunktes"
        ))
    wr.add_register(
        U32(40895, "Inverter.UtilCrvCfg.Crv0.CrvTms",
            "Kennlinie, Einstellzeit des Kennlinienarbeitspunktes"))
    wr.add_register(
        U32(40897, "Inverter.UtilCrvCfg.Crv0.CrvTms",
            "Kennlinie, Einstellzeit des Kennlinienarbeitspunktes"))
    wr.add_register(
        U32(40899, "Inverter.UtilCrvCfg.Crv0.CrvTms",
            "Kennlinie, Einstellzeit des Kennlinienarbeitspunktes"))
    wr.add_register(
        U32(40915, "Inverter.WMax", "Eingestellte Wirkleistungsgrenze"))
    wr.add_register(
        U32(40917, "Inverter.UtilCrvCfg.CrvModCfg.CrvNum",
            "Kennliniennummer, Konfiguration des Kennlinienmodus"))
    wr.add_register(
        U32(40919, "Inverter.UtilCrvCfg.CrvModCfg.CrvNum",
            "Kennliniennummer, Konfiguration des Kennlinienmodus"))
    wr.add_register(
        U32(40921, "Inverter.UtilCrvCfg.CrvModCfg.CrvNum",
            "Kennliniennummer, Konfiguration des Kennlinienmodus"))
    wr.add_register(
        U32(40937, "Inverter.UtilCrvCfg.CrvModCfg.CrvEna",
            "Aktivierung der Kennlinie, Konfiguration des Kennlinienmodus"))
    wr.add_register(
        U32(40939, "Inverter.UtilCrvCfg.CrvModCfg.CrvEna",
            "Aktivierung der Kennlinie, Konfiguration des Kennlinienmodus"))
    wr.add_register(
        U32(40941, "Inverter.UtilCrvCfg.CrvModCfg.CrvEna",
            "Aktivierung der Kennlinie, Konfiguration des Kennlinienmodus"))
    wr.add_register(
        U32(40957, "Inverter.UtilCrvCfg.Crv0.XRef",
            "Kennlinie X-Achsen Referenz"))
    wr.add_register(
        U32(40959, "Inverter.UtilCrvCfg.Crv0.XRef",
            "Kennlinie X-Achsen Referenz"))
    wr.add_register(
        U32(40961, "Inverter.UtilCrvCfg.Crv0.XRef",
            "Kennlinie X-Achsen Referenz"))
    wr.add_register(
        U32(40977, "Inverter.UtilCrvCfg.Crv0.YRef",
            "Kennlinie Y-Achsen Referenz"))
    wr.add_register(
        U32(40979, "Inverter.UtilCrvCfg.Crv0.YRef",
            "Kennlinie Y-Achsen Referenz"))
    wr.add_register(
        U32(40981, "Inverter.UtilCrvCfg.Crv0.YRef",
            "Kennlinie Y-Achsen Referenz"))
    wr.add_register(
        U32(40997, "Inverter.DGSModCfg.HystVolNom",
            "Hysteresespannung, Konfiguration der dynamischen Netzstützung"))
    wr.add_register(
        S32(40999, "Inverter.VArModCfg.PFCtlComCfg.PFEEI",
            "Sollwert cos(Phi) gemäß EEI-Konvention"))
    wr.add_register(U32(41121, "GridGuard.CntrySet", "Setze Ländernorm"))
    wr.add_register(
        U32(41123, "GridGuard.Cntry.VolCtl.ReconMin",
            "Min. Spannung zur Wiederzuschaltung"))
    wr.add_register(
        U32(41125, "GridGuard.Cntry.VolCtl.ReconMax",
            "Max. Spannung zur Wiederzuschaltung"))
    wr.add_register(
        U32(41127, "GridGuard.Cntry.FrqCtl.ReconMin",
            "Untere Frequenz für Wiederzuschaltung"))
    wr.add_register(
        U32(41129, "GridGuard.Cntry.FrqCtl.ReconMax",
            "Obere Frequenz für Wiederzuschaltung"))
    wr.add_register(U32(41131, "DcCfg.StrVol", "minimale Spannung Eingang "))
    wr.add_register(U32(41133, "DcCfg.StrVol", "minimale Spannung Eingang "))
    wr.add_register(U32(41155, "DcCfg.StrTms", "Startverzögerung Eingang "))
    wr.add_register(U32(41157, "DcCfg.StrTms", "Startverzögerung Eingang "))
    wr.add_register(
        U32(41169, "GridGuard.Cntry.LeakRisMin",
            "Minimaler Isolationswiderstand"))
    wr.add_register(U32(41171, "Metering.TotkWhOutSet", "Setze Gesamtertrag"))
    wr.add_register(
        U32(41173, "Metering.TotOpTmhSet",
            "Setze Gesamte Betriebszeit am Netzanschlusspunkt"))
    wr.add_register(
        U32(41187, "Inverter.CtlComCfg.CtlMsSrc",
            "Quelle der Referenzmessung zur Blind-/Wirkleistungsregelung"))
    wr.add_register(
        U32(41193, "Inverter.CtlComCfg.WCtlCom.CtlComMssMod",
            "Betriebsart für ausbleibende Wirkleistungsbegrenzung"))
    wr.add_register(
        U32(41195, "Inverter.CtlComCfg.WCtlCom.TmsOut",
            "Timeout für ausbleibende Wirkleistungsbegrenzung"))
    wr.add_register(
        U32(
            41197, "Inverter.CtlComCfg.WCtlCom.FlbWNom",
            "Fallback Wirkleistungsbegrenzung P in % von WMax für ausbleibende Wirkleistungsbegrenzung"
        ))
    wr.add_register(
        U32(41199, "PCC.WMaxNom",
            "Eingestellte Wirkleistungsgrenze am Netzanschlusspunkt"))
    wr.add_register(U32(41203, "Plnt.DcWRtg", "Anlagen-Nennleistung"))
    wr.add_register(
        S32(41215, "Inverter.WModCfg.WCtlComCfg.FlbWSpt",
            "Fallback Leistung für Betriebsart WCtlCom"))
    wr.add_register(
        U32(41217, "PCC.WMax",
            "Eingestellte Wirkleistungsgrenze am Netzanschlusspunkt"))
    wr.add_register(
        U32(41219, "Inverter.CtlComCfg.VArCtlCom.CtlComMssMod",
            "Betriebsart für ausbleibende Blindleistungsregelung"))
    wr.add_register(
        U32(41221, "Inverter.CtlComCfg.VArCtlCom.TmsOut",
            "Timeout für ausbleibende Blindleistungsregelung"))
    wr.add_register(
        S32(
            41223, "Inverter.CtlComCfg.VArCtlCom.FlbVArNom",
            "Fallback Blindleistung Q in % von WMax für ausbleibende Blindleistungsregelung"
        ))
    wr.add_register(
        U32(41225, "Inverter.CtlComCfg.PFCtlCom.CtlComMssMod",
            "Betriebsart für ausbleibende cos Phi-Vorgabe"))
    wr.add_register(
        U32(41227, "Inverter.CtlComCfg.PFCtlCom.TmsOut",
            "Timeout für ausbleibende cos Phi-Vorgabe"))
    wr.add_register(
        S32(41229, "Inverter.CtlComCfg.PFCtlCom.FlbPF",
            "Fallback cos Phi für ausbleibende cos Phi-Vorgabe"))
    wr.add_register(U32(41253, "Inverter.FstStop", "Schnellabschaltung"))
    wr.add_register(
        S16(41255, "Inverter.WModCfg.WCtlComCfg.WNomPrc",
            "Normierte Wirkleistungsbegrenzung durch Anlagensteuerung"))
    wr.add_register(
        S16(41256, "Inverter.VArModCfg.VArCtlComCfg.VArNomPrc",
            "Normierte Blindleistungsbegrenzung durch Anlagensteuerung"))
    wr.add_register(
        S32(41257, "Inverter.VArModCfg.PFCtlComCfg.PFEEI",
            "Sollwert cos(Phi) gemäß EEI-Konvention"))
示例#12
0
class RootWidget(FloatLayout):
    buttons_is_disable = False

    sync_param_process = False

    com_num = 1
    motor = Modbus()

    speed = -1
    accel_time = -1
    deccel_time = -1

    auto_speed = -1
    auto_accel_time = -1
    auto_deccel_time = -1

    manual_speed = -1
    manual_accel_time = -1
    manual_deccel_time = -1

    work_time = -1
    reverse = False
    auto_presets = []
    manual_presets = []
    selected_preset = -1

    com_input = ObjectProperty()
    connect_button = ObjectProperty()
    speed_input = ObjectProperty()
    speed_error_img = ObjectProperty()
    accel_time_input = ObjectProperty()
    accel_error_img = ObjectProperty()
    deccel_time_input = ObjectProperty()
    deccel_error_img = ObjectProperty()
    work_time_input = ObjectProperty()
    work_error_img = ObjectProperty()
    motor_switch = ObjectProperty()
    apply_param_button = ObjectProperty()
    preset_button = ObjectProperty()
    add_preset_button = ObjectProperty()
    del_preset_button = ObjectProperty()
    sync_params_button = ObjectProperty()

    def error(self, text):
        ErrorPopup(text)

    def resource_path(self, relative_path):
        print(resource_path(relative_path))
        return resource_path(relative_path)

    def save_params(self):

        with open(appdata_path + 'settings.txt', 'w') as f:
            f.write(str(self.com_num) + '\n')
            f.write(str(self.auto_speed) + '\n')
            f.write(str(self.auto_accel_time) + '\n')
            f.write(str(self.auto_deccel_time) + '\n')
            f.write(str(self.work_time) + '\n')
            f.write(str(self.reverse) + '\n')
            f.write(str(self.manual_speed) + '\n')
            f.write(str(self.manual_accel_time) + '\n')
            f.write(str(self.manual_deccel_time) + '\n')

    def load_params(self):
        try:
            f = open(appdata_path + 'settings.txt')
            self.com_num = int(f.readline())
            auto_speed = f.readline().strip()
            if auto_speed != '-1':
                self.speed_input.text = auto_speed
                self.accel_time_input.text = f.readline().strip()
                self.deccel_time_input.text = f.readline().strip()
                self.work_time_input.text = f.readline().strip()
                self.work_time = int(self.work_time_input.text)
                self.reverse = f.readline().strip() == 'True'
            else:
                for i in range(4):
                    f.readline()

            manual_speed = int(f.readline())
            if manual_speed != -1:
                self.manual_speed = manual_speed
                self.manual_accel_time = int(f.readline())
                self.manual_deccel_time = int(f.readline())
            f.close()
        except:
            print('load params error')

    def save_presets(self):
        with open(appdata_path + 'presets.prs', 'wb') as f:
            presets = [self.auto_presets, self.manual_presets]
            pickle.dump(presets, f)

    def load_presets(self):
        try:
            with open(appdata_path + 'presets.prs', 'rb') as f:
                presets = pickle.load(f)
                self.auto_presets = presets[0]
                self.manual_presets = presets[1]
        except:
            self.auto_presets = []
            self.manual_presets = []

    def check_param_equals(self):
        if int(self.speed_input.text) != self.speed:
            self.speed_error_img.color = (1, 1, 1, 1)
        else:
            self.speed_error_img.color = (1, 1, 1, 0)
        if int(self.accel_time_input.text) != self.accel_time:
            self.accel_error_img.color = (1, 1, 1, 1)
        else:
            self.accel_error_img.color = (1, 1, 1, 0)
        if int(self.deccel_time_input.text) != self.deccel_time:
            self.deccel_error_img.color = (1, 1, 1, 1)
        else:
            self.deccel_error_img.color = (1, 1, 1, 0)
        if int(self.work_time_input.text) != self.work_time:
            self.work_error_img.color = (1, 1, 1, 1)
        else:
            self.work_error_img.color = (1, 1, 1, 0)

    def set_param(self, register, value):
        if myApp.auto_mode:
            if register == ServoReg.SPEED:
                self.auto_speed = self.speed = value
                self.speed_input.text = str(value)
            elif register == ServoReg.ACCEL_TIME:
                self.auto_accel_time = self.accel_time = value
                self.accel_time_input.text = str(value)
            elif register == ServoReg.DECCEL_TIME:
                self.auto_deccel_time = self.deccel_time = value
                self.deccel_time_input.text = str(value)
        else:
            if register == ServoReg.SPEED:
                self.manual_speed = self.speed = value
                self.speed_input.text = str(value)
            elif register == ServoReg.ACCEL_TIME:
                self.manual_accel_time = self.accel_time = value
                self.accel_time_input.text = str(value)
            elif register == ServoReg.DECCEL_TIME:
                self.manual_deccel_time = self.deccel_time = value
                self.deccel_time_input.text = str(value)

        if register == ServoReg.DECCEL_TIME and self.sync_param_process:
            self.sync_param_process = False
            if self.motor_switch.active:
                self.disable_buttons(False)

        self.check_param_equals()
        self.save_params()

    def servo_sync_params(self, instance):
        self.sync_param_process = True
        self.disable_buttons(True)
        registers = [ServoReg.SPEED, ServoReg.ACCEL_TIME, ServoReg.DECCEL_TIME]
        for register in registers:

            def check_answer(*args, **kwargs):
                try:
                    ans = kwargs['ans']
                    register = kwargs['register']
                    if ans[:7] == ':010302':
                        myApp.root_widget.set_param(register,
                                                    int(ans[7:11], 16))
                except:
                    pass

            self.motor.get_param(register, check_answer)

    def add_preset_popup(self, instance):
        popup = AddPresetPopup()
        popup.open()

    def add_preset(self, name):
        preset = Preset(name, int(self.speed_input.text),
                        int(self.accel_time_input.text),
                        int(self.deccel_time_input.text),
                        int(self.work_time_input.text))
        if myApp.auto_mode:
            self.auto_presets.append(preset)
        else:
            self.manual_presets.append(preset)
        self.save_presets()
        self.update_presets_dropdown()

    def del_preset(self):
        if self.selected_preset >= 0:
            if myApp.auto_mode:
                del self.auto_presets[self.selected_preset]
            else:
                del self.manual_presets[self.selected_preset]
            self.save_presets()
            self.update_presets_dropdown()
            self.preset_button.text = 'Пресет'

    def del_preset_btn(self, instance):
        if self.selected_preset >= 0:
            quest_popup = QuestionPopup()
            quest_popup.ok_func = self.del_preset
            quest_popup.question.text = 'Вы действительно хотите удалить пресет?'
            quest_popup.open()

    def select_preset(self, instance):
        self.selected_preset = int(instance.id)
        if myApp.auto_mode:
            preset = self.auto_presets[self.selected_preset]
        else:
            preset = self.manual_presets[self.selected_preset]
        self.preset_button.text = instance.text
        self.speed_input.text = str(preset.speed)
        self.accel_time_input.text = str(preset.accel_time)
        self.deccel_time_input.text = str(preset.deccel_time)
        self.work_time_input.text = str(preset.work_time)
        self.dropdown.dismiss()
        self.check_param_equals()

    def com_changed(self, instance, value):
        try:
            if len(instance.text) > 2:
                instance.text = value[:-1]
            self.com_num = int(value)
            self.save_params()
        except:
            instance.text = value[:-1]

    def change_connect(self, instance):
        if not self.motor.is_connect:
            self.connect()
        else:
            self.disconnect()

    def connect(self):
        self.motor.connect(self.com_num, myApp)
        if not self.motor.is_connect:
            pass
        else:
            self.connect_button.text = 'Отключиться'
            self.motor_switch.disabled = False
            self.apply_param_button.disabled = False
            self.sync_params_button.disabled = False
        self.servo_sync_params(None)

    def disconnect(self):
        self.motor.disconnect()
        if not self.motor.is_connect:
            self.connect_button.text = 'Соединиться'
            self.motor_switch.active = False
            self.motor_switch.disabled = True
            self.apply_param_button.disabled = True
            self.sync_params_button.disabled = True
            self.disable_buttons(True)

    def disable_buttons(self, val):
        self.buttons_is_disable = val
        myApp.mode_widget.disable_buttons(val)

    def motor_change_state(self, instance, value):
        if value:

            def check_motor_is_on(*args, **kwargs):
                ans = kwargs['ans']
                right_ans = kwargs['right_ans']
                if ans == right_ans:
                    myApp.root_widget.disable_buttons(not value)

            self.motor.servo_on(func=check_motor_is_on)
        else:
            self.motor.servo_off()
            self.disable_buttons(not value)

    def servo_set_params(self, instance):
        def apply_param(*args, **kwargs):
            ans = kwargs['ans']
            right_ans = kwargs['right_ans']
            if ans == right_ans:
                register = int(ans[5:9], 16)
                value = int(ans[9:13], 16)
                myApp.root_widget.set_param(register, value)

        speed = int(self.speed_input.text)
        accel_time = int(self.accel_time_input.text)
        deccel_time = int(self.deccel_time_input.text)
        values = [speed, accel_time, deccel_time]
        registers = [ServoReg.SPEED, ServoReg.ACCEL_TIME, ServoReg.DECCEL_TIME]
        self.sync_param_process = True
        self.disable_buttons(True)
        for i, val in enumerate(values):
            try:
                if val < 0:
                    val = 0
                if i == 0 and val == 0:
                    val = 100
                self.motor.set_param(register=registers[i],
                                     value=val,
                                     func=apply_param)
            except:
                pass
        try:
            self.work_time = int(self.work_time_input.text)
        except:
            pass
        self.save_params()

    def update_presets_dropdown(self):
        self.preset_button.text = 'Пресет'
        self.selected_preset = -1
        self.dropdown.clear_widgets()
        if myApp.auto_mode:
            presets = self.auto_presets
        else:
            presets = self.manual_presets
        for index, preset in enumerate(presets):
            btn = Button(id=str(index),
                         text=str(preset.name),
                         size_hint_y=None,
                         height=25)
            btn.bind(on_release=self.select_preset)
            self.dropdown.add_widget(btn)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        try:
            self.load_params()
        except:
            pass
        self.load_presets()
        self.com_input.text = str(self.com_num)
        print('com bind')
        self.com_input.bind(text=self.com_changed)
        self.connect_button.bind(on_press=self.change_connect)

        self.motor_switch.bind(active=self.motor_change_state)
        self.motor_switch.disabled = True

        self.dropdown = DropDown()
        self.update_presets_dropdown()
        self.preset_button.bind(on_release=self.dropdown.open)

        print('buttons bind')
        self.add_preset_button.bind(on_press=self.add_preset_popup)
        self.del_preset_button.bind(on_press=self.del_preset_btn)

        self.apply_param_button.bind(on_press=self.servo_set_params)
        self.apply_param_button.disabled = True
        self.sync_params_button.bind(on_press=self.servo_sync_params)
        self.sync_params_button.disabled = True
        print('root_widget builded.')
示例#13
0
class ServolineMotorApp(MainForm):
    reverse = False
    mode = 'auto'
    motor = Modbus()

    auto_speed = 50
    auto_accel_time = 200
    auto_deccel_time = 200
    auto_work_time = 0

    manual_speed = 50
    manual_accel_time = 200
    manual_deccel_time = 200

    auto_groups = []
    auto_groups_id = -1
    auto_presets = []
    manual_presets = []
    auto_presets_id = -1
    manual_presets_id = -1

    sync_param_process = False
    settings_file = DictionaryParser(appdata_path + 'settings.txt')

    def save_params(self):
        params = {'com': self.com.get()}
        auto = {
            'speed': self.auto_speed,
            'accel_time': self.auto_accel_time,
            'deccel_time': self.auto_deccel_time,
            'work_time': self.auto_work_time,
            'preset_id': self.auto_presets_id,
            'group_id': self.auto_groups_id,
            'reverse': self.reverse
        }
        manual = {
            'speed': self.manual_speed,
            'accel_time': self.manual_accel_time,
            'deccel_time': self.manual_deccel_time,
            'preset_id': self.manual_presets_id
        }
        params['auto'] = auto
        params['manual'] = manual
        try:
            self.settings_file.save_dict(params)
        except:
            print('save params error')

    def load_params(self):
        try:
            params = self.settings_file.load_dict()
            self.com.set(params['com'])
            auto = params['auto']
            self.auto_speed = auto['speed']
            self.auto_accel_time = auto['accel_time']
            self.auto_deccel_time = auto['deccel_time']
            self.auto_presets_id = auto['preset_id']
            self.auto_groups_id = auto.get('group_id', -1)
            self.reverse = auto['reverse']

            manual = params['manual']
            self.manual_speed = manual['speed']
            self.manual_accel_time = manual['accel_time']
            self.manual_deccel_time = manual['deccel_time']
            self.manual_presets_id = manual['preset_id']

            self.speed.set(self.auto_speed)
            self.accel_time.set(self.auto_accel_time)
            self.deccel_time.set(self.auto_deccel_time)
            self.work_time.set(self.auto_work_time)
        except:
            print('load params error')

    def save_presets(self):
        id = self.combobox_presets.current()
        if self.mode == 'auto':
            self.auto_presets_id = id
        else:
            self.manual_presets_id = id
        self.save_params()
        with open(appdata_path + 'presets.prs', 'wb') as f:
            presets = [self.auto_presets, self.manual_presets]
            pickle.dump(presets, f)
        with open(appdata_path + 'groups.prs', 'wb') as f:
            pickle.dump(self.auto_groups, f)

    def load_presets(self):
        try:
            with open(appdata_path + 'presets.prs', 'rb') as f:
                presets = pickle.load(f)
                self.auto_presets = presets[0]
                self.manual_presets = presets[1]
        except:
            self.auto_presets = []
            self.manual_presets = []

        try:
            with open(appdata_path + 'groups.prs', 'rb') as f:
                self.auto_groups = pickle.load(f)
        except:
            self.auto_groups = []
            self.auto_groups_id = -1

    def check_param_equals(self):
        pass

    def enable_buttons(self, val):
        self.auto.enable_buttons(val)
        self.manual.enable_buttons(val)

    def change_connect(self):
        if not self.motor.is_connect:
            self.connect()
        else:
            self.disconnect()

    def connect(self):
        self.motor.connect(self.com.get(), self)
        if self.motor.is_connect:
            self.btn_connect['text'] = 'Отключиться'
            self.switch_motor['state'] = 'normal'
        self.servo_sync_params()
        self.preset_var.set('Выбрать пресет')

    def disconnect(self):
        self.motor.disconnect()
        if not self.motor.is_connect:
            self.btn_connect['text'] = 'Подключиться'
            self.switch_motor.set_val(False)
            self.switch_motor['state'] = 'disabled'
            self.enable_buttons(True)

    def motor_change_state(self, value):
        if value:

            def check_motor_is_on(*args, **kwargs):
                ans = kwargs['ans']
                right_ans = kwargs['right_ans']
                if ans == right_ans:
                    self.enable_buttons(value)

            self.motor.servo_on(right_func=check_motor_is_on)
        else:
            self.motor.servo_off()
            self.enable_buttons(value)

    def set_param_in_entry(self, register, value):
        if self.mode == 'auto':
            if register == ServoReg.SPEED:
                self.auto_speed = value
                self.speed.set(value)
            elif register == ServoReg.ACCEL_TIME:
                self.auto_accel_time = value
                self.accel_time.set(value)
            elif register == ServoReg.DECCEL_TIME:
                self.auto_deccel_time = value
                self.deccel_time.set(value)
        else:
            if register == ServoReg.SPEED:
                self.manual_speed = value
                self.speed.set(value)
            elif register == ServoReg.ACCEL_TIME:
                self.manual_accel_time = value
                self.accel_time.set(value)
            elif register == ServoReg.DECCEL_TIME:
                self.manual_deccel_time = value
                self.deccel_time.set(value)

        if register == ServoReg.DECCEL_TIME and self.sync_param_process:
            self.sync_param_process = False
            if self.switch_motor.val:
                self.enable_buttons(True)

        self.check_param_equals()
        self.save_params()

    def servo_sync_params(self):
        self.sync_param_process = True
        registers = [ServoReg.SPEED, ServoReg.ACCEL_TIME, ServoReg.DECCEL_TIME]
        for register in registers:

            def check_answer(*args, **kwargs):
                try:
                    ans = kwargs['ans']
                    register = kwargs['register']
                    if ans[:7] == ':010302':
                        self.set_param_in_entry(register, int(ans[7:11], 16))
                except:
                    pass

            self.motor.get_param(register=register, right_func=check_answer)

    def servo_set_params(self):
        if self.motor.is_connect:

            def apply_param(*args, **kwargs):
                ans = kwargs['ans']
                right_ans = kwargs['right_ans']
                if ans == right_ans:
                    register = int(ans[5:9], 16)
                    value = int(ans[9:13], 16)
                    self.set_param_in_entry(register, value)
                else:
                    self.error('param apply on motor error')

            speed = self.speed.get()
            accel_time = self.accel_time.get()
            deccel_time = self.deccel_time.get()
            values = [speed, accel_time, deccel_time]
            registers = [
                ServoReg.SPEED, ServoReg.ACCEL_TIME, ServoReg.DECCEL_TIME
            ]
            self.sync_param_process = True
            for i, val in enumerate(values):

                def set_param_on_motor(*args, **kwargs):
                    try:
                        ans = kwargs['ans']
                        current_val = kwargs['current_val']
                        register = kwargs['register']
                        # set_param if difference
                        if (ans[:7] == ':010302' and int(ans[7:11], 16) !=
                                current_val) or (ans[:7] != ':010302'):
                            try:
                                if current_val < 0:
                                    current_val = 0
                                if i == 0 and current_val == 0:
                                    current_val = 100
                                self.motor.set_param(register=register,
                                                     value=current_val,
                                                     right_func=apply_param)
                            except:
                                self.error('error set param on motor in if')
                    except:
                        self.error('error set param on motor')

                self.motor.get_param(register=registers[i],
                                     right_func=set_param_on_motor,
                                     current_val=val)

            try:
                self.auto_work_time = int(self.work_time.get())
            except:
                pass
            self.save_params()
            self.enable_buttons(self.switch_motor.val)

    def param_changed(self):
        values = ['speed', 'accel_time', 'deccel_time']
        for val in values:
            if eval('self.' + str(self.mode) + '_' + str(val) +'!=self.' + str(val) + '.get()')or\
                    (self.auto_work_time!=self.work_time.get()):
                self.image_speed_error.place(x=230, y=50)

    def param_change_complete(self):
        values = ['speed', 'accel_time', 'deccel_time']
        for val in values:
            if eval('self.' + str(self.mode) + '_' + str(val) +'!=self.' + str(val) + '.get()')or\
                    (self.auto_work_time!=self.work_time.get()):
                self.save_params()
                self.servo_set_params()
                if self.mode == 'auto':
                    self.auto_presets_id = -1
                else:
                    self.manual_presets_id = -1
                break

        if (self.mode == 'auto' and self.auto_presets_id == -1)or\
                (self.mode == 'manual' and self.manual_presets_id == -1):
            self.preset_var.set('Выбрать пресет')

        self.image_speed_error.place_forget()

    def change_mode(self):
        self.enable_buttons(False)
        if self.mode == 'auto':
            self.mode = 'manual'
            self.auto.hide()
            self.manual.show()
            self.auto_speed = self.speed.get()
            self.auto_accel_time = self.accel_time.get()
            self.auto_deccel_time = self.deccel_time.get()
            self.auto_work_time = self.work_time.get()
            self.speed.set(self.manual_speed)
            self.accel_time.set(self.manual_accel_time)
            self.deccel_time.set(self.manual_deccel_time)
            self.work_time.set(0)
            self.hide_groups_menu()
            id_pres = self.manual_presets_id
            self.update_presets_combobox()
        else:
            self.mode = 'auto'
            self.manual.hide()
            self.auto.show()
            self.manual_speed = self.speed.get()
            self.manual_accel_time = self.accel_time.get()
            self.manual_deccel_time = self.deccel_time.get()
            self.speed.set(self.auto_speed)
            self.accel_time.set(self.auto_accel_time)
            self.deccel_time.set(self.auto_deccel_time)
            self.work_time.set(self.auto_work_time)
            self.show_groups_menu()
            id_pres = self.auto_presets_id
            if self.auto_presets_id > -1:
                self.group_selected(None, pr_sel_index=self.auto_presets_id)
            else:
                self.update_presets_combobox()

        self.servo_set_params()
        if id_pres > -1:
            self.combobox_presets.current(id_pres)
        else:
            self.preset_var.set('Выбрать пресет')

    def show_group_window(self, new=False):
        self.group_master = Toplevel(self.master)
        if new:
            self.group_window = GroupSettingsWindow(self, self.group_master)
        else:
            self.group_window = GroupSettingsWindow(self, self.group_master,
                                                    self.auto_groups_id)

    def show_add_preset_window(self):
        self.add_preset_master = Toplevel(self.master)
        self.add_preset_window = AddPresetWindow(self, self.add_preset_master)

    def show_preset_settings_window(self):
        self.pr_st_master = Toplevel(self.master)
        self.pr_st_window = PresetSettingsWindow(self, self.pr_st_master,
                                                 self.get_cur_preset())

    def get_cur_preset(self):
        index = self.combobox_presets.current()
        if self.mode == 'auto':
            if self.auto_groups_id == -1:
                return self.auto_presets[index]
            else:
                return self.auto_groups[self.auto_groups_id].presets[index]
        else:
            return self.manual_presets[index]

    def get_cur_group(self):
        return self.auto_groups[self.auto_groups_id]

    def add_preset(self, name):
        preset = Preset(name, self.speed.get(), self.accel_time.get(),
                        self.deccel_time.get())
        if self.mode == 'auto':
            preset.work_time = self.work_time.get()
            if self.auto_groups_id == -1:
                self.auto_presets.append(preset)
            else:
                self.auto_groups[self.auto_groups_id].presets.append(preset)
                self.group_selected(None,
                                    len(self.get_cur_group().presets) - 1)
                self.save_presets()
                return
        else:
            self.manual_presets.append(preset)

        self.save_presets()
        self.update_presets_combobox()
        index = len(self.combobox_presets['values']) - 1
        self.combobox_presets.current(index)

    def change_preset(self):
        index = self.combobox_presets.current()
        if self.mode == 'auto':
            preset = self.auto_presets[index]
            preset.work_time = self.work_time.get()
        else:
            preset = self.manual_presets[index]
        preset.speed = self.speed.get()
        preset.accel_time = self.accel_time.get()
        preset.deccel_time = self.deccel_time.get()
        self.save_presets()

    def save_preset(self, preset):
        cur_preset = self.get_cur_preset()
        for attr in cur_preset.__dict__.keys():
            cur_preset.__dict__[attr] = preset.__dict__[attr]
        self.save_presets()
        self.group_selected(None, self.auto_presets_id)

    def del_preset(self):
        index = self.combobox_presets.current()
        if self.mode == 'auto':
            if self.auto_groups_id == -1:
                del self.auto_presets[index]
            else:
                del self.auto_groups[self.auto_groups_id].presets[index]
                self.group_selected(None)
        else:
            del self.manual_presets[index]
        self.update_presets_combobox()
        self.preset_var.set('Выбрать пресет')
        self.save_presets()

    def up_group(self):
        id = self.combobox_preset_groups.current()
        if id > 0 and id < len(self.auto_groups):
            group = self.auto_groups[id]
            self.auto_groups[id] = self.auto_groups[id - 1]
            self.auto_groups[id - 1] = group
            self.update_groups_combobox()
            self.combobox_preset_groups.current(id - 1)
            self.auto_groups_id = self.combobox_preset_groups.current()
            self.save_presets()

    def down_group(self):
        id = self.combobox_preset_groups.current()
        if id > -1 and id < len(self.auto_groups) - 1:
            group = self.auto_groups[id]
            self.auto_groups[id] = self.auto_groups[id + 1]
            self.auto_groups[id + 1] = group
            self.update_groups_combobox()
            self.combobox_preset_groups.current(id + 1)
            self.auto_groups_id = self.combobox_preset_groups.current()
            self.save_presets()

    def up_preset(self):
        if self.mode == 'manual' or self.auto_groups_id == -1:
            preset_list = eval('self.' + self.mode + '_presets')
        else:
            preset_list = self.get_cur_group().presets
        id = self.combobox_presets.current()
        if id > 0 and id < len(preset_list):
            preset = preset_list[id]
            preset_list[id] = preset_list[id - 1]
            preset_list[id - 1] = preset
            self.update_presets_combobox()
            self.combobox_presets.current(id - 1)
            self.auto_presets_id = self.combobox_presets.current()
            self.save_presets()

    def down_preset(self):
        if self.mode == 'manual' or self.auto_groups_id == -1:
            preset_list = eval('self.' + self.mode + '_presets')
        else:
            preset_list = self.get_cur_group().presets
        id = self.combobox_presets.current()
        if id > -1 and id < len(preset_list) - 1:
            preset = preset_list[id]
            preset_list[id] = preset_list[id + 1]
            preset_list[id + 1] = preset
            self.update_presets_combobox()
            self.combobox_presets.current(id + 1)
            self.auto_presets_id = self.combobox_presets.current()
            self.save_presets()

    def group_selected(self, event, pr_sel_index=0):
        index = self.combobox_preset_groups.current()
        self.auto_groups_id = index
        if self.mode == 'auto':
            group = self.auto_groups[index]
            self.update_presets_combobox()
            if len(group.presets) > 0:
                self.combobox_presets.current(pr_sel_index)
                self.preset_selected(None)
            else:
                self.preset_var.set('Нет пресетов')

    def save_group(self, name, presets_ids, group_id=-1):
        presets = [self.auto_presets[pr_id] for pr_id in presets_ids]
        if group_id < 0:
            group = Group(name, presets)
            self.auto_groups.append(group)
        else:
            self.auto_groups[group_id].name = name
            self.auto_groups[group_id].presets = presets
        self.save_presets()
        self.update_groups_combobox()
        if group_id < 0:
            self.combobox_preset_groups.current(len(self.auto_groups) - 1)
        else:
            self.combobox_preset_groups.current(group_id)
        self.group_selected(None)

    def delete_group(self, id):
        self.auto_groups.pop(id)
        self.auto_groups_id = -1
        self.save_params()
        self.save_presets()
        self.update_groups_combobox()
        self.update_presets_combobox()

    def preset_selected(self, event):
        preset = self.get_cur_preset()
        if self.mode == 'auto':
            self.auto_speed = preset.speed
            self.auto_accel_time = preset.accel_time
            self.auto_deccel_time = preset.deccel_time
            self.auto_work_time = preset.work_time
            self.auto_presets_id = self.combobox_presets.current()
        else:
            self.manual_speed = preset.speed
            self.manual_accel_time = preset.accel_time
            self.manual_deccel_time = preset.deccel_time
            self.manual_presets_id = self.combobox_presets.current()
        self.speed.set(preset.speed)
        self.accel_time.set(preset.accel_time)
        self.deccel_time.set(preset.deccel_time)
        if hasattr(preset, 'work_time'):
            self.work_time.set(preset.work_time)
        else:
            self.work_time.set(0)

        self.servo_set_params()
        self.save_params()

    def update_groups_combobox(self):
        group_names = []
        for group in self.auto_groups:
            group_names.append(group.name)
        self.combobox_preset_groups['values'] = group_names

        if len(group_names) == 0:
            self.preset_groups_var.set('Все пресеты')

    def update_presets_combobox(self):
        preset_names = []
        if self.mode == 'auto':
            if self.auto_groups_id > -1:
                group = self.auto_groups[self.auto_groups_id]
                preset_list = group.presets
            else:
                preset_list = self.auto_presets
        else:
            preset_list = self.manual_presets
        for preset in preset_list:
            preset_names.append(preset.name)
        self.combobox_presets['values'] = preset_names

    def show_notify_window(self, title, text):
        self.notify_master = Toplevel(self.master)
        self.notify_window = NotifyWindow(self, self.notify_master, title,
                                          text)

    def error(self, text):
        self.show_notify_window('Ошибка', text)

    def set_default_settings(self):
        self.preset_var.set('Выбрать пресет')
        self.preset_groups_var.set('Все пресеты')
        self.width = 400
        self.height = 360
        self.master.geometry('%dx%d' % (self.width, self.height))
        self.master.title("Servoline Motor")
        self.master.iconbitmap("icon.ico")
        self.master.resizable(False, False)

    def show_groups_menu(self):
        self.show_element(self.combobox_preset_groups)
        self.show_element(self.btn_group_settings)
        self.show_element(self.btn_group_add)
        self.show_element(self.btn_up_group)
        self.show_element(self.btn_down_group)

    def hide_groups_menu(self):
        self.hide_element(self.combobox_preset_groups)
        self.hide_element(self.btn_group_settings)
        self.hide_element(self.btn_group_add)
        self.hide_element(self.btn_up_group)
        self.hide_element(self.btn_down_group)

    def __init__(self, master):
        self.master = master
        super().__init__(self.master)
        self.set_default_settings()
        self.load_params()
        self.load_presets()
        self.update_groups_combobox()
        if self.auto_groups_id > -1:
            self.combobox_preset_groups.current(self.auto_groups_id)
        self.update_presets_combobox()
        if self.auto_presets_id > -1:
            self.combobox_presets.current(self.auto_presets_id)
            preset = self.auto_presets[self.auto_presets_id]
            self.speed.set(preset.speed)
            self.accel_time.set(preset.accel_time)
            self.deccel_time.set(preset.deccel_time)
            self.work_time.set(preset.work_time)

        self.auto = AutoMode(self)
        self.manual = ManualMode(self)
        self.auto.show()

        self.btn_connect.bind_release(self.change_connect)

        self.switch_motor.bind_sw(self.motor_change_state)
        self.switch_motor.val = True
        self.switch_motor.change_val()

        self.btn_group_settings.bind_release(self.show_group_window)
        self.btn_group_add.bind_release(
            lambda: self.show_group_window(new=True))
        self.btn_up_group.bind_release(self.up_group)
        self.btn_down_group.bind_release(self.down_group)

        self.btn_preset_settings.bind_release(self.show_preset_settings_window)
        self.btn_add_preset.bind_release(self.show_add_preset_window)
        self.btn_up_preset.bind_release(self.up_preset)
        self.btn_down_preset.bind_release(self.down_preset)