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:
@@ -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"/>
|
||||
|
||||
230
revpipycontrol/revpicheckclient.py
Normal file
230
revpipycontrol/revpicheckclient.py
Normal 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()
|
||||
@@ -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):
|
||||
@@ -68,7 +110,25 @@ class RevPiPyControl(tkinter.Frame):
|
||||
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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user