1
0
mirror of https://github.com/naruxde/revpipycontrol.git synced 2025-12-29 11:23:13 +01:00

mktemp auf mkstemp umgestellt

PLC monitor aktiviert
revpicheckclient auf revpipyloader angepasst
Module als einzelnes Fenster anzeigen
This commit is contained in:
2017-06-27 16:12:09 +02:00
parent 099266032c
commit e9279e4a53
13 changed files with 1041 additions and 136 deletions

View File

@@ -9,28 +9,29 @@
import pickle
import tkinter
from argparse import ArgumentParser
from concurrent.futures import ThreadPoolExecutor
from time import sleep
from xmlrpc.client import ServerProxy, Binary, MultiCall
from threading import Lock
from xmlrpc.client import ServerProxy
class RevPiCheckClient(tkinter.Frame):
def __init__(self, master, xmlcli):
def __init__(self, master, xmlcli, xmlmode=0):
"""Instantiiert MyApp-Klasse."""
super().__init__(master)
self.pack(fill="both", expand=True)
# XML-Daten abrufen
self.xmlmode = xmlmode
self.cli = xmlcli
self.cli.psstart()
self.lst_devices = self.cli.ps_devices()
self.dict_inps = pickle.loads(self.cli.ps_inps().data)
self.dict_outs = pickle.loads(self.cli.ps_outs().data)
self.lst_devices = self.cli.get_devicenames()
self.lst_group = []
self.dict_inpvar = {}
self.dict_outvar = {}
self.lk = Lock()
self.autorw = tkinter.BooleanVar()
self.fut_autorw = None
self.dowrite = tkinter.BooleanVar()
# Fenster aufbauen
self._createwidgets()
@@ -38,33 +39,6 @@ class RevPiCheckClient(tkinter.Frame):
# 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 onfrmconf(self, canvas):
canvas.configure(scrollregion=canvas.bbox("all"))
@@ -85,23 +59,34 @@ class RevPiCheckClient(tkinter.Frame):
)
rowcount = 0
for io in self.cli.get_iolist(device, iotype):
# io = [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress,tkinter_var]
if iotype == "inp":
lst_io = self.dict_inps[device]
else:
lst_io = self.dict_outs[device]
for io in lst_io:
# io = [name,bytelen,byteaddr,bmk,bitaddress,(tkinter_var)]
tkinter.Label(s_frame, text=io[0]).grid(
column=0, row=rowcount, sticky="w"
)
if io[7] >= 0:
if io[4] >= 0:
var = tkinter.BooleanVar()
check = tkinter.Checkbutton(s_frame)
check["command"] = \
lambda device=device, io=io: self.chval(device, io)
check["state"] = "disabled" if iotype == "inp" else "normal"
check["text"] = ""
check["variable"] = var
check.grid(column=1, row=rowcount)
else:
var = tkinter.IntVar()
txt = tkinter.Spinbox(s_frame, to=256)
# FIXME: Mehrere Bytes möglich
txt = tkinter.Spinbox(s_frame, to=255 * io[1])
txt["command"] = \
lambda device=device, io=io: self.chval(device, io)
txt["state"] = "disabled" if iotype == "inp" else "normal"
txt["width"] = 4
txt["textvariable"] = var
@@ -109,116 +94,127 @@ class RevPiCheckClient(tkinter.Frame):
# 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 __hidewin(self, win, event=None):
win.withdraw()
def __showwin(self, win):
if win.winfo_viewable():
win.withdraw()
else:
win.deiconify()
def _createwidgets(self):
"""Erstellt den Fensterinhalt."""
# Hauptfenster
self.master.wm_title("RevPi Onlineview")
devgrp = tkinter.LabelFrame(self)
devgrp["text"] = "Devices of RevPi"
devgrp.pack(fill="y", side="left")
for dev in self.lst_devices:
# Variablen vorbereiten
self.dict_inpvar[dev] = []
self.dict_outvar[dev] = []
win = tkinter.Toplevel(self)
win.wm_title(dev[1])
win.protocol(
"WM_DELETE_WINDOW",
lambda win=win: self.__hidewin(win)
)
win.withdraw()
# Devicegruppe erstellen
group = tkinter.LabelFrame(self)
group["text"] = dev
group = tkinter.LabelFrame(win)
group["text"] = dev[1]
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._createiogroup(dev[0], 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")
# Button erstellen
btn = tkinter.Button(devgrp)
btn["command"] = lambda win=win: self.__showwin(win)
btn["text"] = dev[1]
btn.pack(fill="x", padx=10, pady=5)
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")
# Steuerungsfunktionen
cntgrp = tkinter.LabelFrame(self)
cntgrp["text"] = "Control"
cntgrp.pack(fill="y", side="right")
self.btn_read = tkinter.Button(self)
self.btn_read = tkinter.Button(cntgrp)
self.btn_read["text"] = "LESEN"
self.btn_read["command"] = self.readvalues
self.btn_read.pack(side="bottom", fill="x")
self.btn_read.pack(fill="x")
check = tkinter.Checkbutton(self)
check = tkinter.Checkbutton(cntgrp)
check["command"] = self.toggleauto
check["text"] = "autoupdate"
check["text"] = "autorefresh processimage"
check["variable"] = self.autorw
check.pack(side="bottom")
check.pack(anchor="w")
def _readvaluesdev(self, device, iotype):
"""Ruft alle aktuellen Werte fuer das Device ab."""
# Multicall vorbereiten
mc_values = MultiCall(self.cli)
check = tkinter.Checkbutton(cntgrp)
check["state"] = "disabled" if self.xmlmode < 3 else "normal"
check["text"] = "write values to processimage"
check["variable"] = self.dowrite
check.pack(anchor="w")
if iotype == "inp":
lst_ios = self.dict_inpvar[device]
elif iotype == "out":
lst_ios = self.dict_outvar[device]
def chval(self, device, io):
if self.dowrite.get():
with self.lk:
self.cli.ps_setvalue(device, io[0], io[5].get())
for io in lst_ios:
mc_values.get_iovalue(device, io[0])
# Alles neu einlesen wenn nicht AutoRW aktiv ist
if not self.autorw.get():
self.readvalues()
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):
def _readvalues(self):
"""Alle Werte der Inputs und Outputs abrufen."""
# Werte aus Prozessabbild einlesen
self.cli.readprocimg()
# Werte abrufen
with self.lk:
ba_values = bytearray(self.cli.ps_values().data)
for dev in self.lst_devices:
self._readvaluesdev(dev, "inp")
self._readvaluesdev(dev, "out")
# io = [name,bytelen,byteaddr,bmk,bitaddress,(tkinter_var)]
# IO Typ verarbeiten
for iotype in [self.dict_inps, self.dict_outs]:
# ios verarbeiten
for io in iotype[dev[0]]:
# Bytes umwandeln
int_byte = int.from_bytes(
ba_values[io[2]:io[2] + io[1]], byteorder="little"
)
if io[4] >= 0:
# Bit-IO
io[5].set(bool(int_byte & 1 << io[4]))
else:
# Byte-IO
io[5].set(int_byte)
if self.autorw.get():
self.master.after(200, self._readvalues)
def readvalues(self):
if not self.autorw.get():
self._readvalues()
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)
if self.autorw.get():
self._readvalues()
def writevalues(self):
"""Alle Outputs senden."""
pass
#for dev in self.lst_devices:
#self._writevaluesdev(dev)
# Werte in Prozessabbild schreiben
#self.cli.writeprocimg()
# Testdrive
if __name__ == "__main__":
root = tkinter.Tk()
myapp = RevPiCheckClient(root)
myapp.mainloop()
cli = ServerProxy("http://192.168.50.35:55123")
cli.psstart()
tk = tkinter.Tk()
RevPiCheckClient(tk, cli, 3)
tk.mainloop()

View File

@@ -17,7 +17,7 @@ from os import environ
from os import makedirs
from shutil import rmtree
from sys import platform
from tempfile import mktemp, mkdtemp
from tempfile import mkstemp, mkdtemp
from xmlrpc.client import Binary
@@ -363,7 +363,7 @@ class RevPiProgram(tkinter.Frame):
message="Die Übertragung der piCtory Konfiguration "
"wurde erfolgreich ausgeführt")
#Einstellungen speichern
# Einstellungen speichern
self.opt["setpictoryrsc_dir"] = os.path.dirname(fh.name)
self._savedefaults()
elif ec < 0:
@@ -382,7 +382,7 @@ class RevPiProgram(tkinter.Frame):
def picontrolreset(self):
ask = tkmsg.askyesno(
parent=self.master, title="Frage...",
parent=self.master, title="Frage...",
message="Soll piControlReset wirklich durchgeführt werden? \n"
"Das Prozessabbild und die Steuerung werden dann unterbrochen!!!"
)
@@ -415,7 +415,7 @@ class RevPiProgram(tkinter.Frame):
)
if type(dirselect) == str and dirselect != "":
fh = open(mktemp(), "wb")
fh = open(mkstemp(), "wb")
elif tdown == 1:
# Zip

View File

@@ -1,12 +1,13 @@
#!/usr/bin/python3
#
# RevPiPyControl
# Version: 0.2.12
# Version: 0.4.0
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
import revpicheckclient
import revpilogfile
import revpioption
import revpiplclist
@@ -50,6 +51,7 @@ class RevPiPyControl(tkinter.Frame):
self.xmlmode = 0
# Globale Fenster
self.tkcheckclient = None
self.tklogs = None
self.tkoptions = None
self.tkprogram = None
@@ -124,7 +126,7 @@ class RevPiPyControl(tkinter.Frame):
# PLC Menü
self.mplc = tkinter.Menu(self.mbar, tearoff=False)
self.mplc.add_command(label="PLC log...", command=self.plclogs)
#self.mplc.add_command(label="PLC monitor...", command=self.plcmonitor)
self.mplc.add_command(label="PLC monitor...", command=self.plcmonitor)
self.mplc.add_command(label="PLC options...", command=self.plcoptions)
self.mplc.add_command(label="PLC program...", command=self.plcprogram)
self.mbar.add_cascade(label="PLC", menu=self.mplc, state="disabled")
@@ -167,6 +169,8 @@ class RevPiPyControl(tkinter.Frame):
self.mbar.entryconfig("PLC", state="normal")
def _closeall(self):
if self.tkcheckclient is not None:
self.tkcheckclient.destroy()
if self.tklogs is not None:
self.tklogs.master.destroy()
if self.tkoptions is not None:
@@ -191,10 +195,17 @@ class RevPiPyControl(tkinter.Frame):
self.tklogs.focus_set()
def plcmonitor(self):
# TODO: Monitorfenster
pass
"""Startet das Monitorfenster."""
if self.tkcheckclient is None or len(self.tkcheckclient.children) == 0:
win = tkinter.Toplevel(self)
self.tkcheckclient = revpicheckclient.RevPiCheckClient(
win, self.cli, self.xmlmode
)
else:
self.tkcheckclient.focus_set()
def plcoptions(self):
"""Startet das Optionsfenster."""
if self.xmlmode < 2:
tkmsg.showwarning(
parent=self.master, title="Warnung",