1
0
mirror of https://github.com/naruxde/revpipycontrol.git synced 2025-12-28 18:58:03 +01:00

Connection Fenster hinzugef?gt

This commit is contained in:
2017-03-08 14:29:27 +01:00
parent c5ef2ae249
commit 1d2afe8a84
4 changed files with 462 additions and 124 deletions

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd"> <!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpipycontrol --> <!-- eric project file for project revpipycontrol -->
<!-- Saved: 2017-03-03, 16:51:50 --> <!-- Saved: 2017-03-07, 18:53:58 -->
<!-- Copyright (C) 2017 Sven Sager, akira@narux.de --> <!-- Copyright (C) 2017 Sven Sager, akira@narux.de -->
<Project version="5.1"> <Project version="5.1">
<Language>en_US</Language> <Language>en_US</Language>
@@ -19,6 +19,7 @@
<Source>revpipycontrol/revpicheckclient.py</Source> <Source>revpipycontrol/revpicheckclient.py</Source>
<Source>setup.py</Source> <Source>setup.py</Source>
<Source>revpipycontrol/revpiplclist.py</Source> <Source>revpipycontrol/revpiplclist.py</Source>
<Source>revpipycontrol/revpilogfile.py</Source>
</Sources> </Sources>
<Forms/> <Forms/>
<Translations/> <Translations/>
@@ -138,4 +139,83 @@
<FiletypeAssociation pattern="*.pyw" type="SOURCES"/> <FiletypeAssociation pattern="*.pyw" type="SOURCES"/>
<FiletypeAssociation pattern="*.pyw3" type="SOURCES"/> <FiletypeAssociation pattern="*.pyw3" type="SOURCES"/>
</FiletypeAssociations> </FiletypeAssociations>
<Checkers>
<CheckersParams>
<dict>
<key>
<string>Pep8Checker</string>
</key>
<value>
<dict>
<key>
<string>DocstringType</string>
</key>
<value>
<string>pep257</string>
</value>
<key>
<string>ExcludeFiles</string>
</key>
<value>
<string></string>
</value>
<key>
<string>ExcludeMessages</string>
</key>
<value>
<string>E123,E226,E24</string>
</value>
<key>
<string>FixCodes</string>
</key>
<value>
<string></string>
</value>
<key>
<string>FixIssues</string>
</key>
<value>
<bool>False</bool>
</value>
<key>
<string>HangClosing</string>
</key>
<value>
<bool>False</bool>
</value>
<key>
<string>IncludeMessages</string>
</key>
<value>
<string></string>
</value>
<key>
<string>MaxLineLength</string>
</key>
<value>
<int>80</int>
</value>
<key>
<string>NoFixCodes</string>
</key>
<value>
<string>E501</string>
</value>
<key>
<string>RepeatMessages</string>
</key>
<value>
<bool>True</bool>
</value>
<key>
<string>ShowIgnored</string>
</key>
<value>
<bool>False</bool>
</value>
</dict>
</value>
</dict>
</CheckersParams>
</Checkers>
</Project> </Project>

View File

@@ -0,0 +1,73 @@
#
# RevPiPyControl
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
import tkinter
class RevPiLogfile(tkinter.Frame):
def __init__(self, master, xmlcli):
super().__init__(master)
self.pack(fill="both", expand=True)
self.xmlcli = xmlcli
# Fenster bauen
self._createwidgets()
def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Logs")
# PLC Log
self.plclog = tkinter.Text(self)
self.plcscr = tkinter.Scrollbar(self)
self.plclog.pack(side="left", expand=True, fill="both")
self.plcscr.pack(side="left", fill="y")
# self.plclog["state"] = "disabled"
self.plclog["yscrollcommand"] = self.plcscr.set
self.plcscr["command"] = self.plclog.yview
# APP Log
self.applog = tkinter.Text(self)
self.appscr = tkinter.Scrollbar(self)
self.appscr.pack(side="right", fill="y")
self.applog.pack(side="right", expand=True, fill="both")
# self.applog["state"] = "disabled"
self.applog["yscrollcommand"] = self.appscr.set
self.appscr["command"] = self.applog.yview
self.get_applog()
self.get_plclog()
# Timer zum nachladen aktivieren
self.master.after(1000, self.get_applines)
self.master.after(1000, self.get_plclines)
def get_applines(self):
roll = self.applog.yview()[1] == 1.0
for line in self.xmlcli.get_applines():
self.applog.insert(tkinter.END, line)
if roll:
self.applog.see(tkinter.END)
self.master.after(1000, self.get_applines)
def get_applog(self):
self.applog.delete(1.0, tkinter.END)
self.applog.insert(1.0, self.xmlcli.get_applog())
self.applog.see(tkinter.END)
def get_plclines(self):
roll = self.plclog.yview()[1] == 1.0
for line in self.xmlcli.get_plclines():
self.plclog.insert(tkinter.END, line)
if roll:
self.plclog.see(tkinter.END)
self.master.after(1000, self.get_plclines)
def get_plclog(self):
self.plclog.delete(1.0, tkinter.END)
self.plclog.insert(1.0, self.xmlcli.get_plclog())
self.plclog.see(tkinter.END)

View File

@@ -0,0 +1,210 @@
#
# RevPiPyControl
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
import os.path
import pickle
import tkinter
import tkinter.messagebox as tkmsg
from os import environ
from os import makedirs
from sys import platform
# Systemwerte
if platform == "linux":
homedir = environ["HOME"]
else:
homedir = environ["APPDATA"]
savefile = os.path.join(homedir, ".revpipyplc", "connections.dat")
def get_connections():
if os.path.exists(savefile):
fh = open(savefile, "rb")
connections = pickle.load(fh)
return connections
class RevPiPlcList(tkinter.Frame):
def __init__(self, master):
super().__init__(master)
self.pack()
# Daten laden
self._connections = {}
# Fenster bauen
self._createwidgets()
self._loadappdata()
def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Connections")
self.master.wm_resizable(width=False, height=False)
# Listbox mit vorhandenen Verbindungen
self.scr_conn = tkinter.Scrollbar(self)
self.scr_conn.grid(column=1, row=0, rowspan=10, sticky="ns")
self.list_conn = tkinter.Listbox(self, width=20, heigh=15)
self.list_conn.bind("<<ListboxSelect>>", self.evt_listconn)
self.list_conn.grid(column=0, row=0, rowspan=10)
self.list_conn["yscrollcommand"] = self.scr_conn.set
self.scr_conn["command"] = self.list_conn.yview
# Variablen und Defaultwerte
self.var_address = tkinter.StringVar(self)
self.var_port = tkinter.StringVar(self)
self.var_name = tkinter.StringVar(self)
self.var_port.set("55123")
# Eingabefelder für Adresse und Namen
tkinter.Label(self, text="Name").grid(
column=2, row=0, sticky="wn", padx=5, pady=5)
self.txt_name = tkinter.Entry(self, textvariable=self.var_name)
self.txt_name.bind("<KeyRelease>", self.evt_keypress)
self.txt_name.grid(
column=3, row=0, columnspan=3, sticky="n", padx=5, pady=5)
tkinter.Label(self, text="IP-Adresse").grid(
column=2, row=1, sticky="wn", padx=5, pady=5
)
self.txt_address = tkinter.Entry(self, textvariable=self.var_address)
self.txt_address.bind("<KeyRelease>", self.evt_keypress)
self.txt_address.grid(
column=3, row=1, columnspan=3, sticky="n", padx=5, pady=5)
tkinter.Label(self, text="Port").grid(
column=2, row=2, sticky="wn", padx=5, pady=5)
self.txt_port = tkinter.Entry(self, textvariable=self.var_port)
self.txt_port.bind("<KeyRelease>", self.evt_keypress)
self.txt_port.grid(
column=3, row=2, columnspan=3, sticky="n", padx=5, pady=5)
# Listenbutton
self.btn_new = tkinter.Button(
self, text="Neu", command=self.evt_btnnew)
self.btn_new.grid(column=2, row=3, sticky="s")
self.btn_add = tkinter.Button(
self, text="Übernehmen", command=self.evt_btnadd, state="disabled")
self.btn_add.grid(column=3, row=3, sticky="s")
self.btn_remove = tkinter.Button(
self, text="Entfernen", command=self.evt_btnremove, state="disabled")
self.btn_remove.grid(column=4, row=3, sticky="s")
# Fensterbuttons
self.btn_save = tkinter.Button(
self, text="Speichern", command=self.evt_btnsave)
self.btn_save.grid(column=3, row=9, sticky="se")
self.btn_close = tkinter.Button(
self, text="Schließen", command=self.evt_btnclose)
self.btn_close.grid(column=4, row=9, sticky="se")
def _loadappdata(self):
if os.path.exists(savefile):
fh = open(savefile, "rb")
self._connections = pickle.load(fh)
self.build_listconn()
def _saveappdata(self):
try:
makedirs(os.path.dirname(savefile), exist_ok=True)
fh = open(savefile, "wb")
pickle.dump(self._connections, fh)
except:
return False
return True
def build_listconn(self):
self.list_conn.delete(0, "end")
lst_conns = sorted(self._connections.keys(), key=lambda x: x.lower())
self.list_conn.insert("end",*lst_conns)
def evt_btnadd(self):
# TODO: Daten prüfen
self._connections[self.var_name.get()] = \
(self.var_address.get(), self.var_port.get())
self.build_listconn()
self.evt_btnnew()
def evt_btnclose(self):
ask = tkmsg.askyesno(
"Frage...",
"Wollen Sie wirklich beenden?\n"
"Nicht gespeicherte Änderungen gehen verloren",
parent=self.master
)
if ask:
self.master.destroy()
def evt_btnnew(self):
self.list_conn.select_clear(0, "end")
self.evt_listconn()
self.btn_add["state"] = "disabled"
self.var_address.set("")
self.var_name.set("")
self.var_port.set("55123")
def evt_btnremove(self):
item_index = self.list_conn.curselection()
if len(item_index) == 1:
item = self.list_conn.get(item_index[0])
ask = tkmsg.askyesno(
"Frage",
"Wollen Sie die Ausgewählte Verbindung '{}' wirklich "
"löschen?".format(item),
parent=self.master
)
if ask:
# Daten löschen
del self._connections[item]
self.build_listconn()
self.evt_btnnew()
def evt_btnsave(self):
if self._saveappdata():
ask = tkmsg.askyesno(
"Information", "Verbindungen erfolgreich gespeichert.\n"
"Möchten Sie dieses Fenster jetzt schließen?",
parent=self.master
)
if ask:
self.master.destroy()
else:
tkmsg.showerror(
"Fehler", "Verbindungen konnten nicht gespeichert werden",
parent=self.master
)
def evt_listconn(self, evt=None):
item_index = self.list_conn.curselection()
if len(item_index) == 1:
# Daten lesen
item = self.list_conn.get(item_index[0])
self.var_name.set(item)
self.var_address.set(self._connections[item][0])
self.var_port.set(self._connections[item][1])
self.btn_add["state"] == "normal"
self.btn_remove["state"] = "normal"
else:
self.btn_remove["state"] = "disabled"
def evt_keypress(self, evt=None):
okvalue = "normal" if (self.var_address.get() != ""
and self.var_name.get() != ""
and self.var_port.get() != ""
) else "disabled"
self.btn_add["state"] = okvalue
if __name__ == "__main__":
root = tkinter.Tk()
myapp = RevPiPlcList(root)
myapp.mainloop()

View File

@@ -3,77 +3,19 @@
# RevPiPyControl # RevPiPyControl
# Version: 0.2.0 # Version: 0.2.0
# #
# Webpage: https://revpimodio.org/ # Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3 # (c) Sven Sager, License: LGPLv3
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import revpicheckclient import revpicheckclient
import revpilogfile
import revpiplclist
import socket
import tkinter import tkinter
from argparse import ArgumentParser import tkinter.messagebox as tkmsg
from xmlrpc.client import ServerProxy, Binary from xmlrpc.client import ServerProxy
socket.setdefaulttimeout(3)
class RevPiPlcLogs(tkinter.Frame):
def __init__(self, master, xmlcli):
super().__init__(master)
self.pack(fill="both", expand=True)
self.xmlcli = xmlcli
self._createwidgets()
def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Logs")
# PLC Log
self.plclog = tkinter.Text(self)
self.plcscr = tkinter.Scrollbar(self)
self.plclog.pack(side="left", expand=True, fill="both")
self.plcscr.pack(side="left", fill="y")
# self.plclog["state"] = "disabled"
self.plclog["yscrollcommand"] = self.plcscr.set
self.plcscr["command"] = self.plclog.yview
# APP Log
self.applog = tkinter.Text(self)
self.appscr = tkinter.Scrollbar(self)
self.appscr.pack(side="right", fill="y")
self.applog.pack(side="right", expand=True, fill="both")
# self.applog["state"] = "disabled"
self.applog["yscrollcommand"] = self.appscr.set
self.appscr["command"] = self.applog.yview
self.get_applog()
self.get_plclog()
# Timer zum nachladen aktivieren
self.master.after(1000, self.get_applines)
self.master.after(1000, self.get_plclines)
def get_applines(self):
roll = self.applog.yview()[1] == 1.0
for line in self.xmlcli.get_applines():
self.applog.insert(tkinter.END, line)
if roll:
self.applog.see(tkinter.END)
self.master.after(1000, self.get_applines)
def get_applog(self):
self.applog.delete(1.0, tkinter.END)
self.applog.insert(1.0, self.xmlcli.get_applog())
self.applog.see(tkinter.END)
def get_plclines(self):
roll = self.plclog.yview()[1] == 1.0
for line in self.xmlcli.get_plclines():
self.plclog.insert(tkinter.END, line)
if roll:
self.plclog.see(tkinter.END)
self.master.after(1000, self.get_plclines)
def get_plclog(self):
self.plclog.delete(1.0, tkinter.END)
self.plclog.insert(1.0, self.xmlcli.get_plclog())
self.plclog.see(tkinter.END)
class RevPiPyControl(tkinter.Frame): class RevPiPyControl(tkinter.Frame):
@@ -82,23 +24,8 @@ class RevPiPyControl(tkinter.Frame):
super().__init__(master) super().__init__(master)
self.pack(fill="both", expand=True) self.pack(fill="both", expand=True)
# Command arguments self.cli = None
parser = ArgumentParser( self.dict_conn = revpiplclist.get_connections()
description="Revolution Pi IO-Client"
)
parser.add_argument(
"-a", "--address", dest="address", default="127.0.0.1",
help="Server address (Default: 127.0.0.1)"
)
parser.add_argument(
"-p", "--port", dest="port", type=int, default=55123,
help="Use port to connect to server (Default: 55074)"
)
self.pargs = parser.parse_args()
self.cli = ServerProxy(
"http://{}:{}".format(self.pargs.address, self.pargs.port)
)
# Fenster aufbauen # Fenster aufbauen
self._createwidgets() self._createwidgets()
@@ -106,31 +33,41 @@ class RevPiPyControl(tkinter.Frame):
# Daten aktualisieren # Daten aktualisieren
self.tmr_plcrunning() self.tmr_plcrunning()
def _btnstate(self):
stateval = "disabled" if self.cli is None else "normal"
self.btn_plclogs["state"] = stateval
self.btn_plcstart["state"] = stateval
self.btn_plcstop["state"] = stateval
self.btn_plcrestart["state"] = stateval
def _createwidgets(self): def _createwidgets(self):
"""Erstellt den Fensterinhalt.""" """Erstellt den Fensterinhalt."""
# Hauptfenster # Hauptfenster
self.master.wm_title("RevPi Python PLC Loader") self.master.wm_title("RevPi Python PLC Loader")
self.master.wm_resizable(width=False, height=False)
self.var_opt = tkinter.StringVar() # Menü ganz oben
self.var_opt = tkinter.StringVar(self)
self.lst_opt = [ self.lst_opt = [
"Verbindungen...", "Connections...",
"------------------", "------------------",
"PLC Log...", "PLC log...",
"PLC Monitor...", "PLC monitor...",
"PLC Optionen...", "PLC options...",
"PLC program...",
"------------------", "------------------",
"Beenden", "Exit",
] ]
self.opt_menu = tkinter.OptionMenu( self.opt_menu = tkinter.OptionMenu(
self, self.var_opt, *self.lst_opt, command=self._opt_do self, self.var_opt, *self.lst_opt, command=self._opt_do)
)
self.opt_menu.pack(fill="x") self.opt_menu.pack(fill="x")
self.var_conn = tkinter.StringVar() # Verbindungen
self.txt_conn = tkinter.Entry(self) self.var_conn = tkinter.StringVar(self)
self.txt_conn["state"] = "readonly" self.lst_conn = sorted(self.dict_conn.keys(), key=lambda x: x.lower())
self.txt_conn["textvariable"] = self.var_conn self.opt_conn = tkinter.OptionMenu(
self.txt_conn.pack() self, self.var_conn, *self.lst_conn, command=self._opt_conn)
self.opt_conn.pack(fill="x")
self.btn_plcstart = tkinter.Button(self) self.btn_plcstart = tkinter.Button(self)
self.btn_plcstart["text"] = "PLC Start" self.btn_plcstart["text"] = "PLC Start"
@@ -147,28 +84,38 @@ class RevPiPyControl(tkinter.Frame):
self.btn_plcrestart["command"] = self.plcrestart self.btn_plcrestart["command"] = self.plcrestart
self.btn_plcrestart.pack(fill="x") self.btn_plcrestart.pack(fill="x")
# self.btn_plcrestart = tkinter.Button(self) self.btn_plclogs = tkinter.Button(self)
# self.btn_plcrestart["text"] = "PLC Monitor" self.btn_plclogs["text"] = "PLC Logs"
# self.btn_plcrestart["command"] = self.plcmonitor self.btn_plclogs["command"] = self.plclogs
# self.btn_plcrestart.pack(fill="x") self.btn_plclogs.pack(fill="x")
self.btn_plcrestart = tkinter.Button(self) self.var_status = tkinter.StringVar(self)
self.btn_plcrestart["text"] = "PLC Logs"
self.btn_plcrestart["command"] = self.plclogs
self.btn_plcrestart.pack(fill="x")
self.var_status = tkinter.StringVar()
self.txt_status = tkinter.Entry(self) self.txt_status = tkinter.Entry(self)
self.txt_status["state"] = "readonly" self.txt_status["state"] = "readonly"
self.txt_status["textvariable"] = self.var_status self.txt_status["textvariable"] = self.var_status
self.txt_status.pack() self.txt_status.pack()
def _opt_conn(self, text):
sp = ServerProxy(
"http://{}:{}".format(
self.dict_conn[text][0], int(self.dict_conn[text][1])
)
)
# Server prüfen
try:
sp.system.listMethods()
except:
self.servererror()
else:
self.cli = sp
def _opt_do(self, text): def _opt_do(self, text):
optselect = self.lst_opt.index(text) optselect = self.lst_opt.index(text)
if optselect == 0: if optselect == 0:
# Verbindungen # Verbindungen
pass self.plclist()
elif optselect == 2: elif optselect == 2:
# Logs
self.plclogs() self.plclogs()
elif optselect == 3: elif optselect == 3:
pass pass
@@ -176,17 +123,27 @@ class RevPiPyControl(tkinter.Frame):
elif optselect == 4: elif optselect == 4:
# Optionen # Optionen
pass pass
elif optselect == 6: elif optselect == 5:
# Programm updown
pass
elif optselect == 7:
self.master.destroy() self.master.destroy()
self.var_opt.set("") self.var_opt.set("")
def plclist(self):
win = tkinter.Toplevel(self)
revpiplclist.RevPiPlcList(win)
win.focus_set()
win.grab_set()
self.wait_window(win)
def plclogs(self): def plclogs(self):
root = tkinter.Tk() win = tkinter.Toplevel(self)
self.tklogs = RevPiPlcLogs(root, self.cli) self.tklogs = revpilogfile.RevPiLogfile(win, self.cli)
def plcmonitor(self): def plcmonitor(self):
root = tkinter.Tk() #self.tkmonitor = revpicheckclient.RevPiCheckClient(self.master, self.cli)
self.tkmonitor = revpicheckclient.RevPiCheckClient(root, self.cli) pass
def plcstart(self): def plcstart(self):
self.cli.plcstart() self.cli.plcstart()
@@ -198,15 +155,33 @@ class RevPiPyControl(tkinter.Frame):
self.cli.plcstop() self.cli.plcstop()
self.cli.plcstart() self.cli.plcstart()
def servererror(self):
self.cli = None
self._btnstate()
self.var_conn.set("")
tkmsg.showerror("Fehler", "Server ist nicht erreichbar!")
def tmr_plcrunning(self): def tmr_plcrunning(self):
self._btnstate()
if self.cli is None:
self.txt_status["readonlybackground"] = "lightblue"
self.var_status.set("NOT CONNECTED")
else:
try:
if self.cli.plcrunning(): if self.cli.plcrunning():
self.txt_status["readonlybackground"] = "green" self.txt_status["readonlybackground"] = "green"
else: else:
self.txt_status["readonlybackground"] = "red" self.txt_status["readonlybackground"] = "red"
plcec = self.cli.plcexitcode() plcec = self.cli.plcexitcode()
except:
self.var_status.set("SERVER ERROR")
self.servererror()
else:
if plcec == -1: if plcec == -1:
plcec = "RUNNING" plcec = "RUNNING"
elif plcec == -2:
plcec = "FILE NOT FOUND"
elif plcec == 0: elif plcec == 0:
plcec = "NOT RUNNING" plcec = "NOT RUNNING"
self.var_status.set(plcec) self.var_status.set(plcec)
@@ -217,4 +192,4 @@ class RevPiPyControl(tkinter.Frame):
if __name__ == "__main__": if __name__ == "__main__":
root = tkinter.Tk() root = tkinter.Tk()
myapp = RevPiPyControl(root) myapp = RevPiPyControl(root)
myapp.mainloop() root.mainloop()