1
0
mirror of https://github.com/naruxde/revpipycontrol.git synced 2025-11-08 15:43:52 +01:00

simple log viewer

This commit is contained in:
2017-02-26 18:36:34 +01:00
parent e49b48c36e
commit ed23ce2b48
3 changed files with 406 additions and 12 deletions

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpipycontrol -->
<!-- Saved: 2017-02-15, 20:52:17 -->
<!-- Saved: 2017-02-26, 18:33:07 -->
<!-- Copyright (C) 2017 Sven Sager, akira@narux.de -->
<Project version="5.1">
<Language>en_US</Language>
@@ -16,6 +16,7 @@
<Sources>
<Source>revpipycontrol/__init__.py</Source>
<Source>revpipycontrol/revpipycontrol.py</Source>
<Source>revpipycontrol/revpicheckclient.py</Source>
</Sources>
<Forms/>
<Translations/>
@@ -23,7 +24,110 @@
<Interfaces/>
<Others/>
<Vcs>
<VcsType>None</VcsType>
<VcsType>Mercurial</VcsType>
<VcsOptions>
<dict>
<key>
<string>add</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>checkout</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>commit</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>diff</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>export</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>global</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>history</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>log</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>remove</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>status</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>tag</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
<key>
<string>update</string>
</key>
<value>
<list>
<string></string>
</list>
</value>
</dict>
</VcsOptions>
<VcsOtherData>
<dict/>
</VcsOtherData>
</Vcs>
<FiletypeAssociations>
<FiletypeAssociation pattern="*.idl" type="INTERFACES"/>

View File

@@ -0,0 +1,230 @@
# Thranks to: http://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter
import pickle
import tkinter
from argparse import ArgumentParser
from concurrent.futures import ThreadPoolExecutor
from time import sleep
from xmlrpc.client import ServerProxy, Binary, MultiCall
class RevPiCheckClient(tkinter.Frame):
def __init__(self, master, xmlcli=None):
"""Instantiiert MyApp-Klasse."""
super().__init__(master)
self.pack(fill="both", expand=True)
# Command arguments
parser = ArgumentParser(
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=55074,
help="Use port to connect to server (Default: 55074)"
)
self.pargs = parser.parse_args()
self.cli = xmlcli if xmlcli is not None else ServerProxy(
"http://{}:{}".format(self.pargs.address, self.pargs.port)
)
self.lst_devices = self.cli.get_devicenames()
self.lst_group = []
self.dict_inpvar = {}
self.dict_outvar = {}
self.autorw = tkinter.BooleanVar()
self.fut_autorw = None
# Fenster aufbauen
self._createwidgets()
# Aktuelle Werte einlesen
self.readvalues()
def _autorw(self):
dict_inp = {}
dict_out = {}
while self.autorw.get():
for dev in self.lst_devices:
try:
dict_out[dev] = [
value[8].get() for value in self.dict_outvar[dev]
]
except:
print("lasse {} aus".format(dev))
dict_inp = self.cli.refreshvalues(
Binary(pickle.dumps(dict_out, 3))
)
dict_inp = pickle.loads(dict_inp.data)
for dev in dict_inp:
for io in self.dict_inpvar[dev]:
try:
io[8].set(dict_inp[dev].pop(0))
except:
print("lasse {} aus".format(io[0]))
sleep(0.1)
def onFrameConfigure(self, canvas):
canvas.configure(scrollregion=canvas.bbox("all"))
def _createiogroup(self, device, frame, iotype):
"""Erstellt IO-Gruppen."""
# IOs generieren
canvas = tkinter.Canvas(frame, borderwidth=0, width=180, heigh=800)
s_frame = tkinter.Frame(canvas)
vsb = tkinter.Scrollbar(frame, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4, 4), window=s_frame, anchor="nw")
s_frame.bind("<Configure>", lambda event, canvas=canvas: self.onFrameConfigure(canvas))
rowcount = 0
for io in self.cli.get_iolist(device, iotype):
# io = [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress,tkinter_var]
tkinter.Label(s_frame, text=io[0]).grid(column=0, row=rowcount, sticky="w")
if io[7] >= 0:
var = tkinter.BooleanVar()
check = tkinter.Checkbutton(s_frame)
check["state"] = "disabled" if iotype == "inp" else "normal"
check["text"] = ""
check["variable"] = var
check.grid(column=1, row=rowcount)
#check.pack(anchor="e", side="right")
else:
var = tkinter.IntVar()
#txt = tkinter.Spinbox(fra_group, to=256)
txt = tkinter.Spinbox(s_frame, to=256)
txt["state"] = "disabled" if iotype == "inp" else "normal"
txt["width"] = 4
txt["textvariable"] = var
txt.grid(column=1, row=rowcount)
#txt.pack(anchor="e", side="right")
# Steuerelementvariable in IO übernehmen
io.append(var)
if iotype == "inp":
self.dict_inpvar[device].append(io)
elif iotype == "out":
self.dict_outvar[device].append(io)
rowcount += 1
def _createwidgets(self):
"""Erstellt den Fensterinhalt."""
# Hauptfenster
self.master.wm_title("RevPi Onlineview")
for dev in self.lst_devices:
# Variablen vorbereiten
self.dict_inpvar[dev] = []
self.dict_outvar[dev] = []
# Devicegruppe erstellen
group = tkinter.LabelFrame(self)
group["text"] = dev
group.pack(side="left", fill="both", expand=True)
self.lst_group.append(group)
for iotype in ["inp", "out"]:
frame = tkinter.Frame(group)
frame.pack(side="left", fill="both", expand=True)
self._createiogroup(dev, frame, iotype)
# self.btn_update = tkinter.Button(self)
# self.btn_update["text"] = "UPDATE"
# self.btn_update["command"] = self._autorw
# self.btn_update.pack(anchor="s", side="bottom", fill="x")
self.btn_write = tkinter.Button(self)
self.btn_write["text"] = "SCHREIBEN"
self.btn_write["command"] = self.writevalues
self.btn_write.pack(side="bottom", fill="x")
self.btn_read = tkinter.Button(self)
self.btn_read["text"] = "LESEN"
self.btn_read["command"] = self.readvalues
self.btn_read.pack(side="bottom", fill="x")
check = tkinter.Checkbutton(self)
check["command"] = self.toggleauto
check["text"] = "autoupdate"
check["variable"] = self.autorw
check.pack(side="bottom")
def _readvaluesdev(self, device, iotype):
"""Ruft alle aktuellen Werte fuer das Device ab."""
# Multicall vorbereiten
mc_values = MultiCall(self.cli)
if iotype == "inp":
lst_ios = self.dict_inpvar[device]
elif iotype == "out":
lst_ios = self.dict_outvar[device]
for io in lst_ios:
mc_values.get_iovalue(device, io[0])
i = 0
for value in mc_values():
value = pickle.loads(value.data)
if type(value) == bytes:
value = int.from_bytes(value, byteorder="little")
lst_ios[i][8].set(value)
i += 1
def _writevaluesdev(self, device):
"""Sendet Werte der Outputs fuer ein Device."""
# Multicall vorbereiten
mc_values = MultiCall(self.cli)
lst_ios = lst_ios = self.dict_outvar[device]
for io in lst_ios:
mc_values.set_iovalue(device, io[0], pickle.dumps(io[8].get(), 3))
# Multicall ausführen
mc_values()
def readvalues(self):
"""Alle Werte der Inputs und Outputs abrufen."""
# Werte aus Prozessabbild einlesen
self.cli.readprocimg()
for dev in self.lst_devices:
self._readvaluesdev(dev, "inp")
self._readvaluesdev(dev, "out")
def toggleauto(self):
self.btn_read["state"] = "disabled" if self.autorw.get() else "normal"
self.btn_write["state"] = "disabled" if self.autorw.get() else "normal"
if self.autorw.get() and (self.fut_autorw is None or self.fut_autorw.done()):
e = ThreadPoolExecutor(max_workers=1)
self.fut_autorw = e.submit(self._autorw)
def writevalues(self):
"""Alle Outputs senden."""
pass
#for dev in self.lst_devices:
#self._writevaluesdev(dev)
# Werte in Prozessabbild schreiben
#self.cli.writeprocimg()
if __name__ == "__main__":
root = tkinter.Tk()
myapp = RevPiCheckClient(root)
myapp.mainloop()

View File

@@ -3,11 +3,53 @@
# (c) Sven Sager, License: GPLv3
#
# -*- coding: utf-8 -*-
import revpicheckclient
import tkinter
from argparse import ArgumentParser
from concurrent.futures import ThreadPoolExecutor
from xmlrpc.client import ServerProxy, Binary
class RevPiPyLogs(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["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["yscrollcommand"] = self.appscr.set
self.appscr["command"] = self.applog.yview
self.get_applog()
self.get_plclog()
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_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):
def __init__(self, master=None):
@@ -34,7 +76,7 @@ class RevPiPyControl(tkinter.Frame):
# Fenster aufbauen
self._createwidgets()
# Daten aktualisieren
self.plcrunning()
@@ -42,44 +84,62 @@ class RevPiPyControl(tkinter.Frame):
"""Erstellt den Fensterinhalt."""
# Hauptfenster
self.master.wm_title("RevPi Python PLC Loader")
self.var_status = tkinter.StringVar()
self.txt_status = tkinter.Entry()
self.txt_status["textvariable"] = self.var_status
self.txt_status.pack(fill="x")
self.btn_plcrunning = tkinter.Button(self)
self.btn_plcrunning["text"] = "PLC Status"
self.btn_plcrunning["command"] = self.plcrunning
self.btn_plcrunning.pack(fill="x")
self.btn_plcstart = tkinter.Button(self)
self.btn_plcstart["text"] = "PLC Start"
self.btn_plcstart["command"] = self.plcstart
self.btn_plcstart.pack(fill="x")
self.btn_plcstop = tkinter.Button(self)
self.btn_plcstop["text"] = "PLC Stop"
self.btn_plcstop["command"] = self.plcstop
self.btn_plcstop.pack(fill="x")
self.btn_plcrestart = tkinter.Button(self)
self.btn_plcrestart["text"] = "PLC Restart"
self.btn_plcrestart["command"] = self.plcrestart
self.btn_plcrestart.pack(fill="x")
def plcstart(self):
# self.btn_plcrestart = tkinter.Button(self)
# self.btn_plcrestart["text"] = "PLC Monitor"
# self.btn_plcrestart["command"] = self.plcmonitor
# self.btn_plcrestart.pack(fill="x")
self.btn_plcrestart = tkinter.Button(self)
self.btn_plcrestart["text"] = "PLC Logs"
self.btn_plcrestart["command"] = self.plclogs
self.btn_plcrestart.pack(fill="x")
def plclogs(self):
root = tkinter.Tk()
self.tklogs = RevPiPyLogs(root, self.cli)
def plcmonitor(self):
root = tkinter.Tk()
self.tkmonitor = revpicheckclient.RevPiCheckClient(root, self.cli)
def plcstart (self):
self.cli.plcstart()
self.plcrunning()
def plcstop(self):
self.cli.plcstop()
self.plcrunning()
def plcrestart(self):
self.cli.plcrestart()
self.plcrunning()
def plcrunning(self):
if self.cli.plcrunning():
self.btn_plcrunning["activebackground"] = "green"