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

29 Commits
0.2.7 ... 0.4.1

Author SHA1 Message Date
efbde10c02 Fenster/Button Beschriftung in watch-modus mit Positionsnummer 2017-07-04 08:29:11 +02:00
c20dc479a2 Etikett 0.4.1 gel?scht 2017-07-04 08:28:27 +02:00
587247f048 Etikett 0.4.1 zu ?nderungssatz c6bddb1ad26f verschoben (aus dem ?nderungssatz df45b47d647b) 2017-07-03 20:11:45 +02:00
9e9751883d Bugfix: Automatische Sprachwahl 2017-07-03 20:11:34 +02:00
6103104d96 Bugfix: Automatische Sprachwahl 2017-07-03 18:22:26 +02:00
45e3414f94 Etikett 0.4.1 zu ?nderungssatz df45b47d647b verschoben (aus dem ?nderungssatz 087ad4db05f4) 2017-07-03 17:03:41 +02:00
f52dc05be2 LC_MESSAGES fehlten in deb paket 2017-07-03 17:03:09 +02:00
f58be573c4 Etikett 0.4.1 zum ?nderungssatz 087ad4db05f4 hinzugef?gt 2017-07-03 13:17:54 +02:00
5488107c42 Maximale Bytel?nge f?r int() berechnung festgelegt 32Bit Systeme 2017-07-03 12:59:55 +02:00
03773ff4b0 Mit procimgserver zusammenf?hren 2017-07-03 10:40:58 +02:00
cdaff8fe4e Translation 2017-07-03 10:40:22 +02:00
7fc879bbe1 RevPiCheckClient Fehler z?hlen und ggf. Fenster verwerfen
RevPiCheckControl baut RevPiCheckClient nach max Fehler neu auf
2017-07-02 22:21:29 +02:00
15b59be6d8 Bugfix: RevPiLogfile ignoriert bei Dienstneustart xml exception
Bugfix: RevPiOption ignorierte Abbrechen-Schaltfl?che beim speichern
Bugfix: WindowHandling bei gesicherten Fenstern
Bugfix: Optionsspeicherung und neustart RevPiCheckclient
Designanpassungen
locale in setup ?bernommen
2017-07-02 11:36:17 +02:00
145468d35b Sortierung der Devices beibehalten
RevPiOption Einstellungen in globalem dc
RevPiOption Interaktion bei Meldungen verbessert
RevPiCheckClient auf kleine xml Einstellungen angepasst
RevPiInfo Text-Feld angepasst auf kleine xml Einstellung
bugfix: RevPiPyControl.serverdisconnect()
bugfix: RevPiCheckClient Doppelter Timerstart verhindert
2017-07-01 16:08:11 +02:00
0653c6c8eb docstrings angepasst 2017-07-01 13:37:06 +02:00
256a95aa8b Buxfix: mkstemp Umstellung
R?ckmeldungen bei piCtory Konfiguration detailierter
Info-Fenster eingebunden
2017-06-30 21:06:06 +02:00
1fec478e3f Sicherheitswarnung vor dem Output schreiben integriert
Hauptfenster alles aufr?umen vor destroy()
Wertepr?fung bei RevPiCheckClient int() Werten
Bearbeitungsfunktion bei RevPiCheckClient eingebaut
Hilfemen? mit Webbrowser aufruf eingebaut
2017-06-30 13:50:39 +02:00
a60431e456 RevPiLogfile auf neue Byte?bertragung angepasst
Reaktion auf Fehlerbytes vom RevPi f?r Logfile
In Dialogfenster ESC zum schlie?en eingebaut
_checkclose Funktionen zur Pr?fung auf ?nderung und Schlie?en hinzugef?gt
2017-06-29 20:11:55 +02:00
1f668b153c Codestyle von tkinter.messagebox angepasst 2017-06-29 13:03:39 +02:00
624b6f6972 RevPiPlcList vor Schlie?en sch?tzen
Quelltext f?r ?bersetzung angepasst
?bersetzung mit poedit durchgef?hrt
2017-06-29 12:48:22 +02:00
8c8da29915 IO-Fenster nur in Y resizable
Scrollrad an Canvas gekoppelt (Linux)
Exitcodes angepasst
?bersetzungstools eingebaut
?bersetzungen begonnen
2017-06-29 09:00:19 +02:00
673c338c6b "Monitorfunktion" als Debug zum Hautpfenster hinzugef?gt
Disconnect-Men?eintrag eingebaut (Funktion hinzugef?gt)
Funktionen f?r "nur lesen" und "nur schreiben" eingebaut
Werte schreiben per MultiCall
UI-Texte angepasst
DocStrings und CodeStyle
2017-06-28 11:55:30 +02:00
e9279e4a53 mktemp auf mkstemp umgestellt
PLC monitor aktiviert
revpicheckclient auf revpipyloader angepasst
Module als einzelnes Fenster anzeigen
2017-06-27 16:12:09 +02:00
099266032c Etikett 0.2.12 zum ?nderungssatz 6081e473f267 hinzugef?gt 2017-04-11 12:45:56 +02:00
76c45daaf7 docs 2017-04-11 12:45:42 +02:00
6ebf8ccc0a Logdaten werden als Binary ?bertragen
piControlReset hinzugef?gt
2017-04-11 12:39:48 +02:00
92d73e9c12 Etikett 0.2.8 zum ?nderungssatz f97f08836642 hinzugef?gt 2017-04-11 12:37:20 +02:00
3e2b5f66a9 Einstellungen vom Programmfenster werden gespeichert 2017-03-23 10:44:54 +01:00
2d04617358 Etikett 0.2.7 zum ?nderungssatz 67f6a3937a1f hinzugef?gt 2017-03-20 13:23:09 +01:00
23 changed files with 3860 additions and 500 deletions

View File

@@ -3,6 +3,7 @@ syntax: glob
deb_dist/* deb_dist/*
dist/* dist/*
revpipycontrol.egg-info/* revpipycontrol.egg-info/*
doc/*
deb/* deb/*
.eric6project/* .eric6project/*
*.directory
*.mo

41
doc/index.html Normal file
View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html><head>
<title>Table of contents</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000">
<h1 style="background-color:#FFFFFF;color:#0000FF">
Table of contents</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Modules</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="mytools.html">mytools</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpicheckclient.html">revpicheckclient</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpiinfo.html">revpiinfo</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpilogfile.html">revpilogfile</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpioption.html">revpioption</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpiplclist.html">revpiplclist</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpiprogram.html">revpiprogram</a></td>
<td></td>
</tr><tr>
<td><a style="color:#0000FF" href="revpipycontrol.html">revpipycontrol</a></td>
<td></td>
</tr>
</table>
</body></html>

59
doc/mytools.html Normal file
View File

@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html><head>
<title>mytools</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
mytools</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#addroot">addroot</a></td>
<td>H&#228;ngt root-dir der Anwendung vor Dateinamen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#gettrans">gettrans</a></td>
<td></td>
</tr>
</table>
<hr /><hr />
<a NAME="addroot" ID="addroot"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">addroot</h2>
<b>addroot</b>(<i>filename</i>)
<p>
H&#228;ngt root-dir der Anwendung vor Dateinamen.
</p><p>
Je nach Ausf&#252;hrungsart der Anwendung muss das root-dir &#252;ber
andere Arten abgerufen werden.
</p><dl>
<dt><i>filename</i></dt>
<dd>
Datei oder Ordnername
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
root dir
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="gettrans" ID="gettrans"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">gettrans</h2>
<b>gettrans</b>(<i>proglang=None</i>)
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

313
doc/revpicheckclient.html Normal file
View File

@@ -0,0 +1,313 @@
<!DOCTYPE html>
<html><head>
<title>revpicheckclient</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpicheckclient</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient">RevPiCheckClient</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="RevPiCheckClient" ID="RevPiCheckClient"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiCheckClient</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.__init__">RevPiCheckClient</a></td>
<td>Instantiiert MyApp-Klasse.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.__chval">__chval</a></td>
<td>Schreibt neuen Output Wert auf den RevPi.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.__hidewin">__hidewin</a></td>
<td>Verbergt &#252;bergebenes Fenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.__saveoldvalue">__saveoldvalue</a></td>
<td>Speichert bei Keypress aktuellen Wert f&#252;r wiederherstellung.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.__showwin">__showwin</a></td>
<td>Zeigt oder verbergt &#252;bergebenes Fenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.__spinboxkey">__spinboxkey</a></td>
<td>Pr&#252;ft die Eingabe auf plausibilit&#228;t.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient._createiogroup">_createiogroup</a></td>
<td>Erstellt IO-Gruppen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient._createwidgets">_createwidgets</a></td>
<td>Erstellt den Fensterinhalt.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient._onfrmconf">_onfrmconf</a></td>
<td>Erstellt Fenster in einem Canvas.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient._warnwrite">_warnwrite</a></td>
<td>Warnung f&#252;r Benutzer &#252;ber Schreibfunktion einmal fragen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient._workvalues">_workvalues</a></td>
<td>Alle Werte der Inputs und Outputs abrufen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.hideallwindows">hideallwindows</a></td>
<td>Versteckt alle Fenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.maxint">maxint</a></td>
<td>Errechnet maximalen int() Wert f&#252;r Bytes max 22.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.readvalues">readvalues</a></td>
<td>Ruft nur Input Werte von RevPi ab und aktualisiert Fenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.refreshvalues">refreshvalues</a></td>
<td>Ruft alle IO Werte von RevPi ab und aktualisiert Fenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.tmr_workvalues">tmr_workvalues</a></td>
<td>Timer f&#252;r zyklische Abfrage.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.toggleauto">toggleauto</a></td>
<td>Schaltet zwischen Autorefresh um und aktualisiert Widgets.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.togglewrite">togglewrite</a></td>
<td>Schaltet zwischen DoWrite um und aktiviert Schreibfunktion.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.validatereturn">validatereturn</a></td>
<td>&#220;berpr&#252;ft die R&#252;ckgaben der setvalue Funktion.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiCheckClient.writevalues">writevalues</a></td>
<td>Schreibt ge&#228;nderte Outputs auf den RevPi.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiCheckClient.__init__" ID="RevPiCheckClient.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient (Constructor)</h3>
<b>RevPiCheckClient</b>(<i>master, xmlcli, xmlmode=0</i>)
<p>
Instantiiert MyApp-Klasse.
</p><a NAME="RevPiCheckClient.__chval" ID="RevPiCheckClient.__chval"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.__chval</h3>
<b>__chval</b>(<i>device, io, event=None</i>)
<p>
Schreibt neuen Output Wert auf den RevPi.
</p><a NAME="RevPiCheckClient.__hidewin" ID="RevPiCheckClient.__hidewin"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.__hidewin</h3>
<b>__hidewin</b>(<i>win, event=None</i>)
<p>
Verbergt &#252;bergebenes Fenster.
</p><dl>
<dt><i>win</i></dt>
<dd>
Fenster zum verbergen
</dd><dt><i>event</i></dt>
<dd>
Tkinter Event
</dd>
</dl><a NAME="RevPiCheckClient.__saveoldvalue" ID="RevPiCheckClient.__saveoldvalue"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.__saveoldvalue</h3>
<b>__saveoldvalue</b>(<i>event, tkvar</i>)
<p>
Speichert bei Keypress aktuellen Wert f&#252;r wiederherstellung.
</p><a NAME="RevPiCheckClient.__showwin" ID="RevPiCheckClient.__showwin"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.__showwin</h3>
<b>__showwin</b>(<i>win</i>)
<p>
Zeigt oder verbergt &#252;bergebenes Fenster.
</p><dl>
<dt><i>win</i></dt>
<dd>
Fenster zum anzeigen/verbergen
</dd>
</dl><a NAME="RevPiCheckClient.__spinboxkey" ID="RevPiCheckClient.__spinboxkey"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.__spinboxkey</h3>
<b>__spinboxkey</b>(<i>device, io, event=None</i>)
<p>
Pr&#252;ft die Eingabe auf plausibilit&#228;t.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter Event
</dd><dt><i>io</i></dt>
<dd>
IO Liste mit tkinter Variable
</dd>
</dl><a NAME="RevPiCheckClient._createiogroup" ID="RevPiCheckClient._createiogroup"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient._createiogroup</h3>
<b>_createiogroup</b>(<i>device, frame, iotype</i>)
<p>
Erstellt IO-Gruppen.
</p><dl>
<dt><i>device</i></dt>
<dd>
Deviceposition
</dd><dt><i>frame</i></dt>
<dd>
tkinter Frame
</dd><dt><i>iotype</i></dt>
<dd>
'inp' oder 'out' als str()
</dd>
</dl><a NAME="RevPiCheckClient._createwidgets" ID="RevPiCheckClient._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient._createwidgets</h3>
<b>_createwidgets</b>(<i></i>)
<p>
Erstellt den Fensterinhalt.
</p><a NAME="RevPiCheckClient._onfrmconf" ID="RevPiCheckClient._onfrmconf"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient._onfrmconf</h3>
<b>_onfrmconf</b>(<i>canvas</i>)
<p>
Erstellt Fenster in einem Canvas.
</p><dl>
<dt><i>canvas</i></dt>
<dd>
Canvas in dem Objekte erstellt werden sollen
</dd>
</dl><a NAME="RevPiCheckClient._warnwrite" ID="RevPiCheckClient._warnwrite"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient._warnwrite</h3>
<b>_warnwrite</b>(<i></i>)
<p>
Warnung f&#252;r Benutzer &#252;ber Schreibfunktion einmal fragen.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn Warnung einmal mit OK best&#228;tigt wurde
</dd>
</dl><a NAME="RevPiCheckClient._workvalues" ID="RevPiCheckClient._workvalues"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient._workvalues</h3>
<b>_workvalues</b>(<i>io_dicts=None, writeout=False</i>)
<p>
Alle Werte der Inputs und Outputs abrufen.
</p><dl>
<dt><i>io_dicts</i></dt>
<dd>
Arbeit nur f&#252;r dieses Dict()
</dd><dt><i>writeout</i></dt>
<dd>
&#196;nderungen auf RevPi schreiben
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
None
</dd>
</dl><a NAME="RevPiCheckClient.hideallwindows" ID="RevPiCheckClient.hideallwindows"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.hideallwindows</h3>
<b>hideallwindows</b>(<i></i>)
<p>
Versteckt alle Fenster.
</p><a NAME="RevPiCheckClient.maxint" ID="RevPiCheckClient.maxint"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.maxint</h3>
<b>maxint</b>(<i>bytelen</i>)
<p>
Errechnet maximalen int() Wert f&#252;r Bytes max 22.
</p><dl>
<dt><i>bytelen</i></dt>
<dd>
Anzahl Bytes
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
int() max oder 0 bei &#220;berschreitung
</dd>
</dl><a NAME="RevPiCheckClient.readvalues" ID="RevPiCheckClient.readvalues"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.readvalues</h3>
<b>readvalues</b>(<i></i>)
<p>
Ruft nur Input Werte von RevPi ab und aktualisiert Fenster.
</p><a NAME="RevPiCheckClient.refreshvalues" ID="RevPiCheckClient.refreshvalues"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.refreshvalues</h3>
<b>refreshvalues</b>(<i></i>)
<p>
Ruft alle IO Werte von RevPi ab und aktualisiert Fenster.
</p><a NAME="RevPiCheckClient.tmr_workvalues" ID="RevPiCheckClient.tmr_workvalues"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.tmr_workvalues</h3>
<b>tmr_workvalues</b>(<i></i>)
<p>
Timer f&#252;r zyklische Abfrage.
</p><dl>
<dt>Returns:</dt>
<dd>
None
</dd>
</dl><a NAME="RevPiCheckClient.toggleauto" ID="RevPiCheckClient.toggleauto"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.toggleauto</h3>
<b>toggleauto</b>(<i></i>)
<p>
Schaltet zwischen Autorefresh um und aktualisiert Widgets.
</p><a NAME="RevPiCheckClient.togglewrite" ID="RevPiCheckClient.togglewrite"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.togglewrite</h3>
<b>togglewrite</b>(<i></i>)
<p>
Schaltet zwischen DoWrite um und aktiviert Schreibfunktion.
</p><a NAME="RevPiCheckClient.validatereturn" ID="RevPiCheckClient.validatereturn"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.validatereturn</h3>
<b>validatereturn</b>(<i>returnlist</i>)
<p>
&#220;berpr&#252;ft die R&#252;ckgaben der setvalue Funktion.
</p><dl>
<dt><i>returnlist</i></dt>
<dd>
list() der xml R&#252;ckgabe
</dd>
</dl><a NAME="RevPiCheckClient.writevalues" ID="RevPiCheckClient.writevalues"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiCheckClient.writevalues</h3>
<b>writevalues</b>(<i></i>)
<p>
Schreibt ge&#228;nderte Outputs auf den RevPi.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

99
doc/revpiinfo.html Normal file
View File

@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html><head>
<title>revpiinfo</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpiinfo</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiInfo">RevPiInfo</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="RevPiInfo" ID="RevPiInfo"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiInfo</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiInfo.__init__">RevPiInfo</a></td>
<td>Init RevPiLogfile-Class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiInfo._checkclose">_checkclose</a></td>
<td>Pr&#252;ft ob Fenster beendet werden soll.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiInfo._createwidgets">_createwidgets</a></td>
<td>Erstellt alle Widgets.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiInfo.visitwebsite">visitwebsite</a></td>
<td>&#214;ffnet auf dem System einen Webbrowser zur Projektseite.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiInfo.__init__" ID="RevPiInfo.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiInfo (Constructor)</h3>
<b>RevPiInfo</b>(<i>master, xmlcli, version</i>)
<p>
Init RevPiLogfile-Class.
</p><a NAME="RevPiInfo._checkclose" ID="RevPiInfo._checkclose"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiInfo._checkclose</h3>
<b>_checkclose</b>(<i>event=None</i>)
<p>
Pr&#252;ft ob Fenster beendet werden soll.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter-Event
</dd>
</dl><a NAME="RevPiInfo._createwidgets" ID="RevPiInfo._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiInfo._createwidgets</h3>
<b>_createwidgets</b>(<i>extended=False</i>)
<p>
Erstellt alle Widgets.
</p><a NAME="RevPiInfo.visitwebsite" ID="RevPiInfo.visitwebsite"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiInfo.visitwebsite</h3>
<b>visitwebsite</b>(<i>event=None</i>)
<p>
&#214;ffnet auf dem System einen Webbrowser zur Projektseite.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

164
doc/revpilogfile.html Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html><head>
<title>revpilogfile</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpilogfile</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiLogfile">RevPiLogfile</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="RevPiLogfile" ID="RevPiLogfile"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiLogfile</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiLogfile.__init__">RevPiLogfile</a></td>
<td>Init RevPiLogfile-Class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile._checkclose">_checkclose</a></td>
<td>Pr&#252;ft ob Fenster beendet werden soll.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile._createwidgets">_createwidgets</a></td>
<td>Erstellt alle Widgets.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile._load_log">_load_log</a></td>
<td>L&#228;d die angegebenen Logfiles herunter.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile.btn_clearapp">btn_clearapp</a></td>
<td>Leert die Logliste der App.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile.btn_clearplc">btn_clearplc</a></td>
<td>Leert die Logliste des PLC.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile.get_applog">get_applog</a></td>
<td>Ruft App Logbuch ab.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiLogfile.get_plclog">get_plclog</a></td>
<td>Ruft PLC Logbuch ab.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiLogfile.__init__" ID="RevPiLogfile.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile (Constructor)</h3>
<b>RevPiLogfile</b>(<i>master, xmlcli</i>)
<p>
Init RevPiLogfile-Class.
</p><a NAME="RevPiLogfile._checkclose" ID="RevPiLogfile._checkclose"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile._checkclose</h3>
<b>_checkclose</b>(<i>event=None</i>)
<p>
Pr&#252;ft ob Fenster beendet werden soll.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter-Event
</dd>
</dl><a NAME="RevPiLogfile._createwidgets" ID="RevPiLogfile._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile._createwidgets</h3>
<b>_createwidgets</b>(<i></i>)
<p>
Erstellt alle Widgets.
</p><a NAME="RevPiLogfile._load_log" ID="RevPiLogfile._load_log"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile._load_log</h3>
<b>_load_log</b>(<i>textwidget, xmlcall, startposition, full</i>)
<p>
L&#228;d die angegebenen Logfiles herunter.
</p><dl>
<dt><i>textwidget</i></dt>
<dd>
Widget in das Logs eingef&#252;gt werden sollen
</dd><dt><i>xmlcall</i></dt>
<dd>
xmlrpc Funktion zum Abrufen der Logdaten
</dd><dt><i>startposition</i></dt>
<dd>
Startposition ab der Logdaten kommen sollen
</dd><dt><i>full</i></dt>
<dd>
Komplettes Logbuch laden
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Ende der Datei (neue Startposition)
</dd>
</dl><a NAME="RevPiLogfile.btn_clearapp" ID="RevPiLogfile.btn_clearapp"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile.btn_clearapp</h3>
<b>btn_clearapp</b>(<i></i>)
<p>
Leert die Logliste der App.
</p><a NAME="RevPiLogfile.btn_clearplc" ID="RevPiLogfile.btn_clearplc"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile.btn_clearplc</h3>
<b>btn_clearplc</b>(<i></i>)
<p>
Leert die Logliste des PLC.
</p><a NAME="RevPiLogfile.get_applog" ID="RevPiLogfile.get_applog"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile.get_applog</h3>
<b>get_applog</b>(<i>full=False</i>)
<p>
Ruft App Logbuch ab.
</p><dl>
<dt><i>full</i></dt>
<dd>
Ganzes Logbuch laden
</dd>
</dl><a NAME="RevPiLogfile.get_plclog" ID="RevPiLogfile.get_plclog"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiLogfile.get_plclog</h3>
<b>get_plclog</b>(<i>full=False</i>)
<p>
Ruft PLC Logbuch ab.
</p><dl>
<dt><i>full</i></dt>
<dd>
Ganzes Logbuch laden
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

164
doc/revpioption.html Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html><head>
<title>revpioption</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpioption</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiOption">RevPiOption</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="RevPiOption" ID="RevPiOption"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiOption</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiOption.__init__">RevPiOption</a></td>
<td>Init RevPiOption-Class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption._changesdone">_changesdone</a></td>
<td>Pr&#252;ft ob sich die Einstellungen ge&#228;ndert haben.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption._checkclose">_checkclose</a></td>
<td>Pr&#252;ft ob Fenster beendet werden soll.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption._createwidgets">_createwidgets</a></td>
<td>Erstellt Widgets.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption._loadappdata">_loadappdata</a></td>
<td>L&#228;d aktuelle Einstellungen vom RevPi.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption._setappdata">_setappdata</a></td>
<td>Speichert ge&#228;nderte Einstellungen auf RevPi.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption.askxmlon">askxmlon</a></td>
<td>Fragt Nuter, ob wirklicht abgeschaltet werden soll.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption.xmlmod2_tail">xmlmod2_tail</a></td>
<td>Passt XML-Optionszugriff an.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiOption.xmlmod_tail">xmlmod_tail</a></td>
<td>Passt XML-Optionszugriff an.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiOption.__init__" ID="RevPiOption.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption (Constructor)</h3>
<b>RevPiOption</b>(<i>master, xmlcli</i>)
<p>
Init RevPiOption-Class.
</p><dl>
<dt>Returns:</dt>
<dd>
None
</dd>
</dl><a NAME="RevPiOption._changesdone" ID="RevPiOption._changesdone"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption._changesdone</h3>
<b>_changesdone</b>(<i></i>)
<p>
Pr&#252;ft ob sich die Einstellungen ge&#228;ndert haben.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn min. eine Einstellung ge&#228;ndert wurde
</dd>
</dl><a NAME="RevPiOption._checkclose" ID="RevPiOption._checkclose"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption._checkclose</h3>
<b>_checkclose</b>(<i>event=None</i>)
<p>
Pr&#252;ft ob Fenster beendet werden soll.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter-Event
</dd>
</dl><a NAME="RevPiOption._createwidgets" ID="RevPiOption._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption._createwidgets</h3>
<b>_createwidgets</b>(<i></i>)
<p>
Erstellt Widgets.
</p><a NAME="RevPiOption._loadappdata" ID="RevPiOption._loadappdata"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption._loadappdata</h3>
<b>_loadappdata</b>(<i>refresh=False</i>)
<p>
L&#228;d aktuelle Einstellungen vom RevPi.
</p><dl>
<dt><i>refresh</i></dt>
<dd>
Wenn True, werden Einstellungen heruntergeladen.
</dd>
</dl><a NAME="RevPiOption._setappdata" ID="RevPiOption._setappdata"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption._setappdata</h3>
<b>_setappdata</b>(<i></i>)
<p>
Speichert ge&#228;nderte Einstellungen auf RevPi.
</p><dl>
<dt>Returns:</dt>
<dd>
None
</dd>
</dl><a NAME="RevPiOption.askxmlon" ID="RevPiOption.askxmlon"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption.askxmlon</h3>
<b>askxmlon</b>(<i></i>)
<p>
Fragt Nuter, ob wirklicht abgeschaltet werden soll.
</p><a NAME="RevPiOption.xmlmod2_tail" ID="RevPiOption.xmlmod2_tail"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption.xmlmod2_tail</h3>
<b>xmlmod2_tail</b>(<i></i>)
<p>
Passt XML-Optionszugriff an.
</p><a NAME="RevPiOption.xmlmod_tail" ID="RevPiOption.xmlmod_tail"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiOption.xmlmod_tail</h3>
<b>xmlmod_tail</b>(<i></i>)
<p>
Passt XML-Optionszugriff an.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

188
doc/revpiplclist.html Normal file
View File

@@ -0,0 +1,188 @@
<!DOCTYPE html>
<html><head>
<title>revpiplclist</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpiplclist</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr><tr><td>savefile</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiPlcList">RevPiPlcList</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#get_connections">get_connections</a></td>
<td>Verbindungen aus Datei laden.</td>
</tr>
</table>
<hr /><hr />
<a NAME="RevPiPlcList" ID="RevPiPlcList"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiPlcList</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>myapp</td></tr><tr><td>root</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.__init__">RevPiPlcList</a></td>
<td>Init RevPiPlcList-class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList._checkclose">_checkclose</a></td>
<td>Pr&#252;ft ob Fenster beendet werden soll.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList._createwidgets">_createwidgets</a></td>
<td>Erstellt alle Widgets.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList._saveappdata">_saveappdata</a></td>
<td>Speichert Verbindungen im home Dir.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.build_listconn">build_listconn</a></td>
<td>F&#252;llt Verbindungsliste.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.evt_btnadd">evt_btnadd</a></td>
<td>Verbindungseinstellungen &#252;bernehmen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.evt_btnnew">evt_btnnew</a></td>
<td>Neue Verbindung erstellen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.evt_btnremove">evt_btnremove</a></td>
<td>Verbindung l&#246;schen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.evt_btnsave">evt_btnsave</a></td>
<td>Alle Verbindungen speichern.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.evt_keypress">evt_keypress</a></td>
<td>Passt bei Tastendruck den Status der Buttons an.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPlcList.evt_listconn">evt_listconn</a></td>
<td>&#220;bernimmt Einstellungen in Eingabefelder.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiPlcList.__init__" ID="RevPiPlcList.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList (Constructor)</h3>
<b>RevPiPlcList</b>(<i>master</i>)
<p>
Init RevPiPlcList-class.
</p><dl>
<dt><i>master</i></dt>
<dd>
tkinter master
</dd>
</dl><a NAME="RevPiPlcList._checkclose" ID="RevPiPlcList._checkclose"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList._checkclose</h3>
<b>_checkclose</b>(<i>event=None</i>)
<p>
Pr&#252;ft ob Fenster beendet werden soll.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter-Event
</dd>
</dl><a NAME="RevPiPlcList._createwidgets" ID="RevPiPlcList._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList._createwidgets</h3>
<b>_createwidgets</b>(<i></i>)
<p>
Erstellt alle Widgets.
</p><a NAME="RevPiPlcList._saveappdata" ID="RevPiPlcList._saveappdata"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList._saveappdata</h3>
<b>_saveappdata</b>(<i></i>)
<p>
Speichert Verbindungen im home Dir.
</p><dl>
<dt>Returns:</dt>
<dd>
True, bei erfolgreicher Verarbeitung
</dd>
</dl><a NAME="RevPiPlcList.build_listconn" ID="RevPiPlcList.build_listconn"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.build_listconn</h3>
<b>build_listconn</b>(<i></i>)
<p>
F&#252;llt Verbindungsliste.
</p><a NAME="RevPiPlcList.evt_btnadd" ID="RevPiPlcList.evt_btnadd"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.evt_btnadd</h3>
<b>evt_btnadd</b>(<i></i>)
<p>
Verbindungseinstellungen &#252;bernehmen.
</p><a NAME="RevPiPlcList.evt_btnnew" ID="RevPiPlcList.evt_btnnew"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.evt_btnnew</h3>
<b>evt_btnnew</b>(<i></i>)
<p>
Neue Verbindung erstellen.
</p><a NAME="RevPiPlcList.evt_btnremove" ID="RevPiPlcList.evt_btnremove"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.evt_btnremove</h3>
<b>evt_btnremove</b>(<i></i>)
<p>
Verbindung l&#246;schen.
</p><a NAME="RevPiPlcList.evt_btnsave" ID="RevPiPlcList.evt_btnsave"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.evt_btnsave</h3>
<b>evt_btnsave</b>(<i></i>)
<p>
Alle Verbindungen speichern.
</p><a NAME="RevPiPlcList.evt_keypress" ID="RevPiPlcList.evt_keypress"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.evt_keypress</h3>
<b>evt_keypress</b>(<i>evt=None</i>)
<p>
Passt bei Tastendruck den Status der Buttons an.
</p><a NAME="RevPiPlcList.evt_listconn" ID="RevPiPlcList.evt_listconn"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPlcList.evt_listconn</h3>
<b>evt_listconn</b>(<i>evt=None</i>)
<p>
&#220;bernimmt Einstellungen in Eingabefelder.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="get_connections" ID="get_connections"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">get_connections</h2>
<b>get_connections</b>(<i></i>)
<p>
Verbindungen aus Datei laden.
</p><dl>
<dt>Returns:</dt>
<dd>
dict() mit Verbindungen
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

246
doc/revpiprogram.html Normal file
View File

@@ -0,0 +1,246 @@
<!DOCTYPE html>
<html><head>
<title>revpiprogram</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpiprogram</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr><tr><td>savefile</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiProgram">RevPiProgram</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="RevPiProgram" ID="RevPiProgram"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiProgram</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiProgram.__init__">RevPiProgram</a></td>
<td>Init RevPiProgram-Class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram._checkclose">_checkclose</a></td>
<td>Pr&#252;ft ob Fenster beendet werden soll.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram._createwidgets">_createwidgets</a></td>
<td>Erstellt alle Widgets.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram._evt_optdown">_evt_optdown</a></td>
<td>Passt je nach gew&#228;hlter Option den Status der Widgets an.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram._evt_optup">_evt_optup</a></td>
<td>Passt je nach gew&#228;hlter Option den Status der Widgets an.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram._loaddefault">_loaddefault</a></td>
<td>&#220;bernimmt f&#252;r den Pi die letzen Pfade.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram._savedefaults">_savedefaults</a></td>
<td>Schreibt fuer den Pi die letzen Pfade.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.check_replacedir">check_replacedir</a></td>
<td>Gibt das rootdir von einem entpackten Verzeichnis zurueck.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.create_filelist">create_filelist</a></td>
<td>Erstellt eine Dateiliste von einem Verzeichnis.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.getpictoryrsc">getpictoryrsc</a></td>
<td>L&#228;d die piCtory Konfiguration herunter.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.getprocimg">getprocimg</a></td>
<td>L&#228;d das aktuelle Prozessabbild herunter.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.picontrolreset">picontrolreset</a></td>
<td>F&#252;rt ein Reset der piBridge durch.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.plcdownload">plcdownload</a></td>
<td>L&#228;d das aktuelle Projekt herunter.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.plcupload">plcupload</a></td>
<td>L&#228;dt das angegebene Projekt auf den RevPi.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiProgram.setpictoryrsc">setpictoryrsc</a></td>
<td>&#220;bertr&#228;gt die angegebene piCtory-Konfiguration.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiProgram.__init__" ID="RevPiProgram.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram (Constructor)</h3>
<b>RevPiProgram</b>(<i>master, xmlcli, xmlmode, revpi</i>)
<p>
Init RevPiProgram-Class.
</p><dl>
<dt>Returns:</dt>
<dd>
None
</dd>
</dl><a NAME="RevPiProgram._checkclose" ID="RevPiProgram._checkclose"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram._checkclose</h3>
<b>_checkclose</b>(<i>event=None</i>)
<p>
Pr&#252;ft ob Fenster beendet werden soll.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter-Event
</dd>
</dl><a NAME="RevPiProgram._createwidgets" ID="RevPiProgram._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram._createwidgets</h3>
<b>_createwidgets</b>(<i></i>)
<p>
Erstellt alle Widgets.
</p><a NAME="RevPiProgram._evt_optdown" ID="RevPiProgram._evt_optdown"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram._evt_optdown</h3>
<b>_evt_optdown</b>(<i>text=""</i>)
<p>
Passt je nach gew&#228;hlter Option den Status der Widgets an.
</p><a NAME="RevPiProgram._evt_optup" ID="RevPiProgram._evt_optup"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram._evt_optup</h3>
<b>_evt_optup</b>(<i>text=""</i>)
<p>
Passt je nach gew&#228;hlter Option den Status der Widgets an.
</p><a NAME="RevPiProgram._loaddefault" ID="RevPiProgram._loaddefault"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram._loaddefault</h3>
<b>_loaddefault</b>(<i>full=False</i>)
<p>
&#220;bernimmt f&#252;r den Pi die letzen Pfade.
</p><dl>
<dt><i>full</i></dt>
<dd>
Einstellungen f&#252;r alle Verbindungen laden
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
dict() mit Einstellungen
</dd>
</dl><a NAME="RevPiProgram._savedefaults" ID="RevPiProgram._savedefaults"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram._savedefaults</h3>
<b>_savedefaults</b>(<i></i>)
<p>
Schreibt fuer den Pi die letzen Pfade.
</p><dl>
<dt>Returns:</dt>
<dd>
True, bei erfolgreicher Verarbeitung
</dd>
</dl><a NAME="RevPiProgram.check_replacedir" ID="RevPiProgram.check_replacedir"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.check_replacedir</h3>
<b>check_replacedir</b>(<i>rootdir</i>)
<p>
Gibt das rootdir von einem entpackten Verzeichnis zurueck.
</p><p>
Dabei wird geprueft, ob es sich um einen einzelnen Ordner handelt
und ob es eine piCtory Konfiguration im rootdir gibt.
</p><dl>
<dt><i>rootdir</i></dt>
<dd>
Verzeichnis fuer Pruefung
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Abgeaendertes rootdir
</dd>
</dl><a NAME="RevPiProgram.create_filelist" ID="RevPiProgram.create_filelist"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.create_filelist</h3>
<b>create_filelist</b>(<i>rootdir</i>)
<p>
Erstellt eine Dateiliste von einem Verzeichnis.
</p><dl>
<dt><i>rootdir</i></dt>
<dd>
Verzeichnis fuer das eine Liste erstellt werden soll
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
Dateiliste
</dd>
</dl><a NAME="RevPiProgram.getpictoryrsc" ID="RevPiProgram.getpictoryrsc"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.getpictoryrsc</h3>
<b>getpictoryrsc</b>(<i></i>)
<p>
L&#228;d die piCtory Konfiguration herunter.
</p><a NAME="RevPiProgram.getprocimg" ID="RevPiProgram.getprocimg"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.getprocimg</h3>
<b>getprocimg</b>(<i></i>)
<p>
L&#228;d das aktuelle Prozessabbild herunter.
</p><a NAME="RevPiProgram.picontrolreset" ID="RevPiProgram.picontrolreset"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.picontrolreset</h3>
<b>picontrolreset</b>(<i></i>)
<p>
F&#252;rt ein Reset der piBridge durch.
</p><a NAME="RevPiProgram.plcdownload" ID="RevPiProgram.plcdownload"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.plcdownload</h3>
<b>plcdownload</b>(<i></i>)
<p>
L&#228;d das aktuelle Projekt herunter.
</p><a NAME="RevPiProgram.plcupload" ID="RevPiProgram.plcupload"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.plcupload</h3>
<b>plcupload</b>(<i></i>)
<p>
L&#228;dt das angegebene Projekt auf den RevPi.
</p><dl>
<dt>Returns:</dt>
<dd>
True, bei erfolgreicher Verarbeitung
</dd>
</dl><a NAME="RevPiProgram.setpictoryrsc" ID="RevPiProgram.setpictoryrsc"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiProgram.setpictoryrsc</h3>
<b>setpictoryrsc</b>(<i>filename=None</i>)
<p>
&#220;bertr&#228;gt die angegebene piCtory-Konfiguration.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

270
doc/revpipycontrol.html Normal file
View File

@@ -0,0 +1,270 @@
<!DOCTYPE html>
<html><head>
<title>revpipycontrol</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
revpipycontrol</h1>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>_</td></tr><tr><td>pycontrolversion</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiPyControl">RevPiPyControl</a></td>
<td></td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="RevPiPyControl" ID="RevPiPyControl"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">RevPiPyControl</h2>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
tkinter.Frame
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>myapp</td></tr><tr><td>root</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.__init__">RevPiPyControl</a></td>
<td>Init RevPiPyControl-Class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._btnstate">_btnstate</a></td>
<td>Setzt den state der Buttons.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._closeall">_closeall</a></td>
<td>Schlie&#223;t alle Fenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._closeapp">_closeapp</a></td>
<td>R&#228;umt auf und beendet Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._createwidgets">_createwidgets</a></td>
<td>Erstellt den Fensterinhalt.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._fillconnbar">_fillconnbar</a></td>
<td>Generiert Men&#252;eintr&#228;ge f&#252;r Verbindungen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._fillmbar">_fillmbar</a></td>
<td>Generiert Men&#252;eintr&#228;ge.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl._opt_conn">_opt_conn</a></td>
<td>Stellt eine neue Verbindung zu RevPiPyLoad her.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.infowindow">infowindow</a></td>
<td>&#214;ffnet das Fenster f&#252;r die Info.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plcdebug">plcdebug</a></td>
<td>Baut den Debugframe und packt ihn.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plclist">plclist</a></td>
<td>&#214;ffnet das Fenster f&#252;r die Verbindungen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plclogs">plclogs</a></td>
<td>&#214;ffnet das Fenster f&#252;r Logdateien.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plcoptions">plcoptions</a></td>
<td>Startet das Optionsfenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plcprogram">plcprogram</a></td>
<td>Startet das Programmfenster.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plcrestart">plcrestart</a></td>
<td>Startet das PLC Programm neu.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plcstart">plcstart</a></td>
<td>Startet das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.plcstop">plcstop</a></td>
<td>Beendet das PLC Programm.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.serverdisconnect">serverdisconnect</a></td>
<td>Trennt eine bestehende Verbindung.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.servererror">servererror</a></td>
<td>Setzt alles zur&#252;ck f&#252;r neue Verbindungen.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.tmr_plcrunning">tmr_plcrunning</a></td>
<td>Timer der den Status des PLC Programms pr&#252;ft.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyControl.visitwebsite">visitwebsite</a></td>
<td>&#214;ffnet auf dem System einen Webbrowser zur Projektseite.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="RevPiPyControl.__init__" ID="RevPiPyControl.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl (Constructor)</h3>
<b>RevPiPyControl</b>(<i>master=None</i>)
<p>
Init RevPiPyControl-Class.
</p><dl>
<dt><i>master</i></dt>
<dd>
tkinter master
</dd>
</dl><a NAME="RevPiPyControl._btnstate" ID="RevPiPyControl._btnstate"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._btnstate</h3>
<b>_btnstate</b>(<i></i>)
<p>
Setzt den state der Buttons.
</p><a NAME="RevPiPyControl._closeall" ID="RevPiPyControl._closeall"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._closeall</h3>
<b>_closeall</b>(<i></i>)
<p>
Schlie&#223;t alle Fenster.
</p><a NAME="RevPiPyControl._closeapp" ID="RevPiPyControl._closeapp"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._closeapp</h3>
<b>_closeapp</b>(<i>event=None</i>)
<p>
R&#228;umt auf und beendet Programm.
</p><dl>
<dt><i>event</i></dt>
<dd>
tkinter Event
</dd>
</dl><a NAME="RevPiPyControl._createwidgets" ID="RevPiPyControl._createwidgets"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._createwidgets</h3>
<b>_createwidgets</b>(<i></i>)
<p>
Erstellt den Fensterinhalt.
</p><a NAME="RevPiPyControl._fillconnbar" ID="RevPiPyControl._fillconnbar"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._fillconnbar</h3>
<b>_fillconnbar</b>(<i></i>)
<p>
Generiert Men&#252;eintr&#228;ge f&#252;r Verbindungen.
</p><a NAME="RevPiPyControl._fillmbar" ID="RevPiPyControl._fillmbar"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._fillmbar</h3>
<b>_fillmbar</b>(<i></i>)
<p>
Generiert Men&#252;eintr&#228;ge.
</p><a NAME="RevPiPyControl._opt_conn" ID="RevPiPyControl._opt_conn"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl._opt_conn</h3>
<b>_opt_conn</b>(<i>text, reconnect=False</i>)
<p>
Stellt eine neue Verbindung zu RevPiPyLoad her.
</p><dl>
<dt><i>text</i></dt>
<dd>
Verbindungsname
</dd><dt><i>reconnect</i></dt>
<dd>
Socket Timeout nicht heruntersetzen
</dd>
</dl><a NAME="RevPiPyControl.infowindow" ID="RevPiPyControl.infowindow"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.infowindow</h3>
<b>infowindow</b>(<i></i>)
<p>
&#214;ffnet das Fenster f&#252;r die Info.
</p><a NAME="RevPiPyControl.plcdebug" ID="RevPiPyControl.plcdebug"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plcdebug</h3>
<b>plcdebug</b>(<i></i>)
<p>
Baut den Debugframe und packt ihn.
</p><a NAME="RevPiPyControl.plclist" ID="RevPiPyControl.plclist"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plclist</h3>
<b>plclist</b>(<i></i>)
<p>
&#214;ffnet das Fenster f&#252;r die Verbindungen.
</p><a NAME="RevPiPyControl.plclogs" ID="RevPiPyControl.plclogs"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plclogs</h3>
<b>plclogs</b>(<i></i>)
<p>
&#214;ffnet das Fenster f&#252;r Logdateien.
</p><dl>
<dt>Returns:</dt>
<dd>
None
</dd>
</dl><a NAME="RevPiPyControl.plcoptions" ID="RevPiPyControl.plcoptions"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plcoptions</h3>
<b>plcoptions</b>(<i></i>)
<p>
Startet das Optionsfenster.
</p><a NAME="RevPiPyControl.plcprogram" ID="RevPiPyControl.plcprogram"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plcprogram</h3>
<b>plcprogram</b>(<i></i>)
<p>
Startet das Programmfenster.
</p><a NAME="RevPiPyControl.plcrestart" ID="RevPiPyControl.plcrestart"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plcrestart</h3>
<b>plcrestart</b>(<i></i>)
<p>
Startet das PLC Programm neu.
</p><a NAME="RevPiPyControl.plcstart" ID="RevPiPyControl.plcstart"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plcstart</h3>
<b>plcstart</b>(<i></i>)
<p>
Startet das PLC Programm.
</p><a NAME="RevPiPyControl.plcstop" ID="RevPiPyControl.plcstop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.plcstop</h3>
<b>plcstop</b>(<i></i>)
<p>
Beendet das PLC Programm.
</p><a NAME="RevPiPyControl.serverdisconnect" ID="RevPiPyControl.serverdisconnect"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.serverdisconnect</h3>
<b>serverdisconnect</b>(<i></i>)
<p>
Trennt eine bestehende Verbindung.
</p><a NAME="RevPiPyControl.servererror" ID="RevPiPyControl.servererror"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.servererror</h3>
<b>servererror</b>(<i></i>)
<p>
Setzt alles zur&#252;ck f&#252;r neue Verbindungen.
</p><a NAME="RevPiPyControl.tmr_plcrunning" ID="RevPiPyControl.tmr_plcrunning"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.tmr_plcrunning</h3>
<b>tmr_plcrunning</b>(<i></i>)
<p>
Timer der den Status des PLC Programms pr&#252;ft.
</p><a NAME="RevPiPyControl.visitwebsite" ID="RevPiPyControl.visitwebsite"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyControl.visitwebsite</h3>
<b>visitwebsite</b>(<i></i>)
<p>
&#214;ffnet auf dem System einen Webbrowser zur Projektseite.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

105
revpipycontrol.api Normal file
View File

@@ -0,0 +1,105 @@
mytools.addroot?4(filename)
mytools.gettrans?4(proglang=None)
revpicheckclient.RevPiCheckClient.__chval?6(device, io, event=None)
revpicheckclient.RevPiCheckClient.__hidewin?6(win, event=None)
revpicheckclient.RevPiCheckClient.__saveoldvalue?6(event, tkvar)
revpicheckclient.RevPiCheckClient.__showwin?6(win)
revpicheckclient.RevPiCheckClient.__spinboxkey?6(device, io, event=None)
revpicheckclient.RevPiCheckClient._createiogroup?5(device, frame, iotype)
revpicheckclient.RevPiCheckClient._createwidgets?5()
revpicheckclient.RevPiCheckClient._onfrmconf?5(canvas)
revpicheckclient.RevPiCheckClient._warnwrite?5()
revpicheckclient.RevPiCheckClient._workvalues?5(io_dicts=None, writeout=False)
revpicheckclient.RevPiCheckClient.hideallwindows?4()
revpicheckclient.RevPiCheckClient.maxint?4(bytelen)
revpicheckclient.RevPiCheckClient.readvalues?4()
revpicheckclient.RevPiCheckClient.refreshvalues?4()
revpicheckclient.RevPiCheckClient.tmr_workvalues?4()
revpicheckclient.RevPiCheckClient.toggleauto?4()
revpicheckclient.RevPiCheckClient.togglewrite?4()
revpicheckclient.RevPiCheckClient.validatereturn?4(returnlist)
revpicheckclient.RevPiCheckClient.writevalues?4()
revpicheckclient.RevPiCheckClient?1(master, xmlcli, xmlmode=0)
revpicheckclient._?8
revpiinfo.RevPiInfo._checkclose?5(event=None)
revpiinfo.RevPiInfo._createwidgets?5(extended=False)
revpiinfo.RevPiInfo.visitwebsite?4(event=None)
revpiinfo.RevPiInfo?1(master, xmlcli, version)
revpiinfo._?8
revpilogfile.RevPiLogfile._checkclose?5(event=None)
revpilogfile.RevPiLogfile._createwidgets?5()
revpilogfile.RevPiLogfile._load_log?5(textwidget, xmlcall, startposition, full)
revpilogfile.RevPiLogfile.btn_clearapp?4()
revpilogfile.RevPiLogfile.btn_clearplc?4()
revpilogfile.RevPiLogfile.get_applog?4(full=False)
revpilogfile.RevPiLogfile.get_plclog?4(full=False)
revpilogfile.RevPiLogfile?1(master, xmlcli)
revpilogfile._?8
revpioption.RevPiOption._changesdone?5()
revpioption.RevPiOption._checkclose?5(event=None)
revpioption.RevPiOption._createwidgets?5()
revpioption.RevPiOption._loadappdata?5(refresh=False)
revpioption.RevPiOption._setappdata?5()
revpioption.RevPiOption.askxmlon?4()
revpioption.RevPiOption.xmlmod2_tail?4()
revpioption.RevPiOption.xmlmod_tail?4()
revpioption.RevPiOption?1(master, xmlcli)
revpioption._?8
revpiplclist.RevPiPlcList._checkclose?5(event=None)
revpiplclist.RevPiPlcList._createwidgets?5()
revpiplclist.RevPiPlcList._saveappdata?5()
revpiplclist.RevPiPlcList.build_listconn?4()
revpiplclist.RevPiPlcList.evt_btnadd?4()
revpiplclist.RevPiPlcList.evt_btnnew?4()
revpiplclist.RevPiPlcList.evt_btnremove?4()
revpiplclist.RevPiPlcList.evt_btnsave?4()
revpiplclist.RevPiPlcList.evt_keypress?4(evt=None)
revpiplclist.RevPiPlcList.evt_listconn?4(evt=None)
revpiplclist.RevPiPlcList.myapp?7
revpiplclist.RevPiPlcList.root?7
revpiplclist.RevPiPlcList?1(master)
revpiplclist._?8
revpiplclist.get_connections?4()
revpiplclist.savefile?7
revpiprogram.RevPiProgram._checkclose?5(event=None)
revpiprogram.RevPiProgram._createwidgets?5()
revpiprogram.RevPiProgram._evt_optdown?5(text="")
revpiprogram.RevPiProgram._evt_optup?5(text="")
revpiprogram.RevPiProgram._loaddefault?5(full=False)
revpiprogram.RevPiProgram._savedefaults?5()
revpiprogram.RevPiProgram.check_replacedir?4(rootdir)
revpiprogram.RevPiProgram.create_filelist?4(rootdir)
revpiprogram.RevPiProgram.getpictoryrsc?4()
revpiprogram.RevPiProgram.getprocimg?4()
revpiprogram.RevPiProgram.picontrolreset?4()
revpiprogram.RevPiProgram.plcdownload?4()
revpiprogram.RevPiProgram.plcupload?4()
revpiprogram.RevPiProgram.setpictoryrsc?4(filename=None)
revpiprogram.RevPiProgram?1(master, xmlcli, xmlmode, revpi)
revpiprogram._?8
revpiprogram.savefile?7
revpipycontrol.RevPiPyControl._btnstate?5()
revpipycontrol.RevPiPyControl._closeall?5()
revpipycontrol.RevPiPyControl._closeapp?5(event=None)
revpipycontrol.RevPiPyControl._createwidgets?5()
revpipycontrol.RevPiPyControl._fillconnbar?5()
revpipycontrol.RevPiPyControl._fillmbar?5()
revpipycontrol.RevPiPyControl._opt_conn?5(text, reconnect=False)
revpipycontrol.RevPiPyControl.infowindow?4()
revpipycontrol.RevPiPyControl.myapp?7
revpipycontrol.RevPiPyControl.plcdebug?4()
revpipycontrol.RevPiPyControl.plclist?4()
revpipycontrol.RevPiPyControl.plclogs?4()
revpipycontrol.RevPiPyControl.plcoptions?4()
revpipycontrol.RevPiPyControl.plcprogram?4()
revpipycontrol.RevPiPyControl.plcrestart?4()
revpipycontrol.RevPiPyControl.plcstart?4()
revpipycontrol.RevPiPyControl.plcstop?4()
revpipycontrol.RevPiPyControl.root?7
revpipycontrol.RevPiPyControl.serverdisconnect?4()
revpipycontrol.RevPiPyControl.servererror?4()
revpipycontrol.RevPiPyControl.tmr_plcrunning?4()
revpipycontrol.RevPiPyControl.visitwebsite?4()
revpipycontrol.RevPiPyControl?1(master=None)
revpipycontrol._?8
revpipycontrol.pycontrolversion?7

7
revpipycontrol.bas Normal file
View File

@@ -0,0 +1,7 @@
RevPiCheckClient tkinter.Frame
RevPiInfo tkinter.Frame
RevPiLogfile tkinter.Frame
RevPiOption tkinter.Frame
RevPiPlcList tkinter.Frame
RevPiProgram tkinter.Frame
RevPiPyControl tkinter.Frame

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-20, 12:10:47 --> <!-- Saved: 2017-07-02, 11:35:49 -->
<!-- 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>
@@ -9,7 +9,7 @@
<ProgLanguage mixed="0">Python3</ProgLanguage> <ProgLanguage mixed="0">Python3</ProgLanguage>
<ProjectType>Console</ProjectType> <ProjectType>Console</ProjectType>
<Description></Description> <Description></Description>
<Version>0.2.7</Version> <Version>0.4.1</Version>
<Author>Sven Sager</Author> <Author>Sven Sager</Author>
<Email>akira@narux.de</Email> <Email>akira@narux.de</Email>
<Eol index="-1"/> <Eol index="-1"/>
@@ -21,6 +21,8 @@
<Source>revpipycontrol/revpilogfile.py</Source> <Source>revpipycontrol/revpilogfile.py</Source>
<Source>revpipycontrol/revpioption.py</Source> <Source>revpipycontrol/revpioption.py</Source>
<Source>revpipycontrol/revpiprogram.py</Source> <Source>revpipycontrol/revpiprogram.py</Source>
<Source>revpipycontrol/mytools.py</Source>
<Source>revpipycontrol/revpiinfo.py</Source>
</Sources> </Sources>
<Forms/> <Forms/>
<Translations/> <Translations/>
@@ -29,6 +31,8 @@
<Others> <Others>
<Other>data</Other> <Other>data</Other>
<Other>doc</Other> <Other>doc</Other>
<Other>revpipycontrol.api</Other>
<Other>stdeb.cfg</Other>
</Others> </Others>
<MainScript>revpipycontrol/revpipycontrol.py</MainScript> <MainScript>revpipycontrol/revpipycontrol.py</MainScript>
<Vcs> <Vcs>
@@ -148,24 +152,81 @@
<DocumentationParams> <DocumentationParams>
<dict> <dict>
<key> <key>
<string>ERIC4DOC</string> <string>ERIC4API</string>
</key> </key>
<value> <value>
<dict> <dict>
<key>
<string>ignoreDirectories</string>
</key>
<value>
<list>
<string>data</string>
<string>deb</string>
<string>dist</string>
<string>doc</string>
</list>
</value>
<key> <key>
<string>ignoreFilePatterns</string> <string>ignoreFilePatterns</string>
</key> </key>
<value> <value>
<list> <list>
<string></string> <string>setup.py</string>
</list> </list>
</value> </value>
<key> <key>
<string>noindex</string> <string>includePrivate</string>
</key> </key>
<value> <value>
<bool>True</bool> <bool>True</bool>
</value> </value>
<key>
<string>languages</string>
</key>
<value>
<list>
<string>Python3</string>
</list>
</value>
<key>
<string>outputFile</string>
</key>
<value>
<string>revpipycontrol.api</string>
</value>
<key>
<string>useRecursion</string>
</key>
<value>
<bool>True</bool>
</value>
</dict>
</value>
<key>
<string>ERIC4DOC</string>
</key>
<value>
<dict>
<key>
<string>ignoreDirectories</string>
</key>
<value>
<list>
<string>data</string>
<string>deb</string>
<string>dist</string>
<string>doc</string>
</list>
</value>
<key>
<string>ignoreFilePatterns</string>
</key>
<value>
<list>
<string>setup.py</string>
</list>
</value>
<key> <key>
<string>outputDirectory</string> <string>outputDirectory</string>
</key> </key>

View File

@@ -0,0 +1,722 @@
msgid ""
msgstr ""
"Project-Id-Version: RevPiPyControl 0.4.0\n"
"POT-Creation-Date: 2017-07-03 10:36+0200\n"
"PO-Revision-Date: 2017-07-03 10:36+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.7.1\n"
"X-Poedit-Basepath: ../../..\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-SearchPath-0: .\n"
#: revpicheckclient.py:107 revpicheckclient.py:432 revpioption.py:309
#: revpiplclist.py:205 revpiprogram.py:315 revpiprogram.py:346
#: revpiprogram.py:410 revpiprogram.py:416 revpiprogram.py:422
#: revpiprogram.py:430 revpiprogram.py:436 revpiprogram.py:469
#: revpiprogram.py:553 revpiprogram.py:626 revpiprogram.py:657
#: revpiprogram.py:670 revpiprogram.py:725 revpiprogram.py:745
#: revpiprogram.py:753 revpipycontrol.py:363
msgid "Error"
msgstr "Fehler"
#: revpicheckclient.py:108
msgid ""
"Given value for Output '{}' is not valid! \n"
"Reset to '{}'"
msgstr ""
"Angegebener Wert für Output '{}' ist nicht gültig! \n"
"Setze auf '{}' zurück"
#: revpicheckclient.py:207
msgid "Devices of RevPi"
msgstr "Devices vom RevPi"
#: revpicheckclient.py:239
msgid "Control"
msgstr "Kontrolle"
#: revpicheckclient.py:243
msgid "Read all IOs"
msgstr "Lese alle IOs"
#: revpicheckclient.py:248
msgid "Read just Inputs"
msgstr "Nur Inputs lesen"
#: revpicheckclient.py:255
msgid "Write Outputs"
msgstr "Outputs schreiben"
#: revpicheckclient.py:261
msgid "Autorefresh values"
msgstr "Aktualisiere Werte automatisch"
#: revpicheckclient.py:269
msgid "Write values to RevPi"
msgstr "Schreibe Werte auf RevPi"
#: revpicheckclient.py:283 revpiprogram.py:443 revpipycontrol.py:235
#: revpipycontrol.py:280 revpipycontrol.py:298 revpipycontrol.py:324
msgid "Warning"
msgstr "Warnung"
#: revpicheckclient.py:284
msgid ""
"You want to set outputs on the RevPi! Note that these are set "
"IMMEDIATELY!!! \n"
"If another control program is running on the RevPi, it could interfere and "
"reset the outputs."
msgstr ""
"Sie wollen Outputs auf dem RevPi setzen! Beachten Sie, dass diese SOFORT "
"gesetzt werden!!! \n"
"Wenn auf dem RevPi ein anderes Programm zur Steuerung läuft, könnte dies "
"gestört werden und die Ausgänge wieder zurücksetzen."
#: revpicheckclient.py:429
msgid "Error set value of device '{}' Output '{}': {} \n"
msgstr "Fehler beim Setzen der Werte auf Device '{}' bei Output '{}': {}\n"
#: revpiinfo.py:38
msgid "RevPi Python PLC info"
msgstr "RevPi Python PLC Information"
#: revpiinfo.py:51
msgid "RevPi Python PLC - Control"
msgstr "RevPi Python PLC - Kontrollcenter"
#: revpiinfo.py:55
msgid "Version: {}"
msgstr "Version: {}"
#: revpiinfo.py:78
msgid "RevPiPyLoad version on RevPi:"
msgstr "RevPiPyLoad Version auf RevPi:"
#: revpiinfo.py:83
msgid "not conn."
msgstr "nicht verb."
#: revpiinfo.py:91
msgid ""
"\n"
"RevPiModIO, RevPiPyLoad and RevPiPyControl\n"
"are community driven projects. They are all\n"
"free and open source software.\n"
"All of them comes with ABSOLUTELY NO\n"
"WARRANTY, to the extent permitted by \n"
"applicable law.\n"
"\n"
"\n"
"(c) Sven Sager, License: LGPLv3"
msgstr ""
"\n"
"RevPiModIO, RevPiPyLoad und RevPiPyControl\n"
"sind gemeinschaftsorientierte Projekte. Sie sind\n"
"alle frei und Open Source Software.\n"
"Alle kommen mit ABSOLUT KEINER\n"
"GARANTIE, soweit gesetzlich zulässig.\n"
"\n"
"\n"
"(c) Sven Sager, Lizenz: LGPLv3"
#: revpiinfo.py:138 revpioption.py:232 revpiplclist.py:134
msgid "Close"
msgstr "Schließen"
#: revpilogfile.py:41
msgid "RevPi Python PLC Logs"
msgstr "RevPi Python PLC Logdaten"
#: revpilogfile.py:54
msgid "RevPiPyLoad - Logfile"
msgstr "RevPiPyLoad - Logdatei"
#: revpilogfile.py:58 revpilogfile.py:73
msgid "Clear screen"
msgstr "Leere Ansicht"
#: revpilogfile.py:69
msgid "Python PLC program - Logfile"
msgstr "Python PLC Programm - Logdatei"
#: revpilogfile.py:157
msgid "Can not access log file on the RevPi"
msgstr "Auf die Logdatei des RevPi kann nicht zugegriffen werden"
#: revpioption.py:66 revpioption.py:272 revpioption.py:319 revpiplclist.py:63
#: revpiplclist.py:181 revpiprogram.py:379 revpiprogram.py:454
msgid "Question"
msgstr "Frage"
#: revpioption.py:67 revpiplclist.py:64
msgid ""
"Do you really want to quit? \n"
"Unsaved changes will be lost"
msgstr ""
"Wollen Sie wirklich beenden? \n"
"Nicht gespeicherte Änderungen gehen verloren"
#: revpioption.py:77
msgid "RevPi Python PLC Options"
msgstr "RevPi Python PLC Einstellungen"
#: revpioption.py:87
msgid "Start / Stop behavior"
msgstr "Start / Stop Verhalten"
#: revpioption.py:96
msgid "Start program automatically"
msgstr "Starte Programm automatisch"
#: revpioption.py:102
msgid "Restart program after exit"
msgstr "Starte Programm nach Beenden neu"
#: revpioption.py:110
msgid ""
"Set process image to NULL if program\n"
"terminates successfully"
msgstr ""
"Prozessabbild auf NULL setzen, wenn Programm\n"
"erfolgreich beendet wird"
#: revpioption.py:118
msgid ""
"Set process image to NULL if program\n"
"terminates with errors"
msgstr ""
"Prozessabbild auf NULL setzen, wenn Programm\n"
"fehlerhaft beendet wird"
#: revpioption.py:125
msgid "PLC program"
msgstr "PLC Programm"
#: revpioption.py:136
msgid "Python version"
msgstr "Python Version"
#: revpioption.py:153
msgid "Python PLC program name"
msgstr "Python PLC Programmname"
#: revpioption.py:165
msgid "Program arguments"
msgstr "Programmargumente"
#: revpioption.py:174
msgid "Use RevPi as PLC-Slave"
msgstr "RevPi als PLC-Slave verwenden"
#: revpioption.py:181
msgid "XML-RPC server"
msgstr "XML-RPC Server"
#: revpioption.py:193
msgid "Activate XML-RPC server on RevPi"
msgstr "Aktiviere XML-RPC Server auf RevPi"
#: revpioption.py:201
msgid ""
"Allow download of piCtory configuration and\n"
"PLC programm"
msgstr ""
"Download von piCtroy Konfiguration und\n"
"PLC Programm zulassen"
#: revpioption.py:208
msgid ""
"Allow upload of piCtory configuration and\n"
"PLC programm"
msgstr ""
"Hochladen von piCtroy Konfiguration und\n"
"PLC Programm zulassen"
#: revpioption.py:213
msgid "XML-RPC server port"
msgstr "XML-RPC Serverport"
#: revpioption.py:227 revpiplclist.py:131
msgid "Save"
msgstr "Speichern"
#: revpioption.py:265 revpioption.py:301 revpiplclist.py:197 revpiprogram.py:68
msgid "Information"
msgstr "Information"
#: revpioption.py:266
msgid "You have not made any changes to save."
msgstr "Sie haben keine Änderungen zum Speichern vorgenommen."
#: revpioption.py:273
msgid ""
"The settings are now saved on the Revolution Pi. \n"
"\n"
"Should the new settings take effect immediately? \n"
"This means a restart of the service and the PLC program!"
msgstr ""
"Die Einstellungen werden jetzt auf dem Revolution Pi gespeichert.\n"
"\n"
"Sollen die neuen Einstellungen sofort in Kraft treten?\n"
"Dies bedeutet einen Neustart des Dienstes und des laufenden PLC-Programms!"
#: revpioption.py:302
msgid "Settings saved"
msgstr "Einstellungen gespeichert"
#: revpioption.py:310
msgid "The settings could not be saved. This can happen if values are wrong!"
msgstr ""
"Die Einstellungen konnten nicht gesichert werden. Dies kann passieren, wenn "
"Werte falsch sind!"
#: revpioption.py:320
msgid ""
"Are you sure you want to deactivate the XML-RPC server? You will NOT be able "
"to access the Revolution Pi with this program."
msgstr ""
"Soll der XML-RPC Server wirklich beendet werden? Sie können dann NICHT mehr "
"mit diesem Programm auf den Revolution Pi zugreifen."
#: revpiplclist.py:74
msgid "RevPi Python PLC connections"
msgstr "RevPi Python PLC Verbindungen"
#: revpiplclist.py:94
msgid "Name"
msgstr "Name"
#: revpiplclist.py:101
msgid "IP address"
msgstr "IP Adresse"
#: revpiplclist.py:109
msgid "Port"
msgstr "Port"
#: revpiplclist.py:118
msgid "New"
msgstr "Neu"
#: revpiplclist.py:121
msgid "Apply"
msgstr "Übernehmen"
#: revpiplclist.py:125
msgid "Remove"
msgstr "Entfernen"
#: revpiplclist.py:182
msgid "Do you really want to delete the selected connection '{}'?"
msgstr "Wollen Sie die ausgewählte Verbindung '{}' wirklich löschen?"
#: revpiplclist.py:198
msgid ""
"Successfully saved. \n"
"Do you want to close this window?"
msgstr ""
"Verbindungen erfolgreich gespeichert. \n"
"Möchten Sie dieses Fenster jetzt schließen?"
#: revpiplclist.py:206
msgid "Failed to save connections"
msgstr "Verbindungen konnten nicht gespeichert werden"
#: revpiprogram.py:69
msgid ""
"A PLC program has been uploaded. Please check the PLC options to see if the "
"correct program is specified as the start program."
msgstr ""
"Ein PLC Programm wurde hochgeladen. Bitte prüfen Sie die PLC Optionen, ob "
"dort das richtige Programm als Startprogramm angegeben ist."
#: revpiprogram.py:78
msgid "RevPi Python PLC program"
msgstr "RevPi Python PLC Programm"
#: revpiprogram.py:92
msgid "PLC python program"
msgstr "PLC Python Programm"
#: revpiprogram.py:102 revpiprogram.py:104 revpiprogram.py:112
#: revpiprogram.py:116
msgid "Files"
msgstr "Dateien"
#: revpiprogram.py:102 revpiprogram.py:104 revpiprogram.py:501
#: revpiprogram.py:610
msgid "Zip archive"
msgstr "Zip Archiv"
#: revpiprogram.py:102 revpiprogram.py:104 revpiprogram.py:514
#: revpiprogram.py:640
msgid "TGZ archive"
msgstr "TGZ Archiv"
#: revpiprogram.py:104
msgid "Folder"
msgstr "Verzeichnis"
#: revpiprogram.py:121
msgid "Download PLC program as:"
msgstr "PLC Programm herunterladen als:"
#: revpiprogram.py:131
msgid "include piCtory configuration"
msgstr "inkl. piCtory Konfiguration"
#: revpiprogram.py:136 revpiprogram.py:180 revpiprogram.py:201
msgid "Download"
msgstr "Herunterladen"
#: revpiprogram.py:141
msgid "Upload PLC program as:"
msgstr "PLC Programm hochladen als:"
#: revpiprogram.py:153
msgid "clean upload folder before upload"
msgstr "Uploadverzeichnis vor dem Upload leeren"
#: revpiprogram.py:160
msgid "includes piCtory configuration"
msgstr "enthält piCtory Konfiguration"
#: revpiprogram.py:166 revpiprogram.py:188
msgid "Upload"
msgstr "Hochladen"
#: revpiprogram.py:172
msgid "piCtory configuration"
msgstr "piCtory Konfiguration"
#: revpiprogram.py:176
msgid "Download piCtory configuration"
msgstr "piCtory Konfiguration herunterladen"
#: revpiprogram.py:183
msgid "Upload piCtory configuration"
msgstr "piCtory Konfiguration hochladen"
#: revpiprogram.py:194
msgid "piControl0 process image"
msgstr "piControl0 Prozessabbild"
#: revpiprogram.py:197
msgid "Download process image dump"
msgstr "Prozessabbild Dump herunterladen"
#: revpiprogram.py:207
msgid "Reset piControl"
msgstr "piControl zurücksetzen"
#: revpiprogram.py:210
msgid "Execute piControlReset"
msgstr "piControlReset ausführen"
#: revpiprogram.py:214
msgid "execute"
msgstr "ausführen"
#: revpiprogram.py:220 revpipycontrol.py:107
msgid "Exit"
msgstr "Beenden"
#: revpiprogram.py:305 revpiprogram.py:336 revpiprogram.py:497
#: revpiprogram.py:510
msgid "Save as..."
msgstr "Speichern unter..."
#: revpiprogram.py:308 revpiprogram.py:371
msgid "piCtory config"
msgstr "piCtory Konfiguration"
#: revpiprogram.py:308 revpiprogram.py:339 revpiprogram.py:371
#: revpiprogram.py:501 revpiprogram.py:514 revpiprogram.py:585
#: revpiprogram.py:610 revpiprogram.py:640
msgid "All files"
msgstr "Alle Dateien"
#: revpiprogram.py:316 revpiprogram.py:347 revpiprogram.py:554
msgid "Could not load and save file!"
msgstr "Datei konnte nicht geladen und gespeichert werden!"
#: revpiprogram.py:321 revpiprogram.py:352 revpiprogram.py:391
#: revpiprogram.py:399 revpiprogram.py:463 revpiprogram.py:559
#: revpiprogram.py:715
msgid "Success"
msgstr "Erfolgreich"
#: revpiprogram.py:322 revpiprogram.py:353 revpiprogram.py:560
msgid "File successfully loaded and saved."
msgstr "Dateien erfolgreich übertragen und gespeichert."
#: revpiprogram.py:339
msgid "Imagefiles"
msgstr "Image Dateien"
#: revpiprogram.py:367
msgid "Open piCtory file..."
msgstr "piCtory Datei öffnen..."
#: revpiprogram.py:380
msgid ""
"Should the piControl driver be reset after uploading the piCtory "
"configuration?"
msgstr ""
"Soll nach dem Hochladen der piCtory Konfiguration ein Reset am piControl "
"Treiber durchgeführt werden?"
#: revpiprogram.py:392
msgid ""
"The transfer of the piCtory configuration and the reset of piControl have "
"been successfully executed."
msgstr ""
"Die Übertragung der piCtory Konfiguration und der Reset von piControl wurden "
"erfolgreich ausgeführt."
#: revpiprogram.py:400
msgid "The piCtory configuration was successfully transferred."
msgstr ""
"Die Übertragung der piCtory Konfiguration wurde erfolgreich ausgeführt."
#: revpiprogram.py:411
msgid "Can not process the transferred file."
msgstr "Kann die übertragene Datei nicht verarbeiten."
#: revpiprogram.py:417
msgid "Can not find main elements in piCtory file."
msgstr "Kann Hauptelemente in piCtory datei nicht finden."
#: revpiprogram.py:423
msgid ""
"Contained devices could not be found on Revolution Pi. The configuration may "
"be from a newer piCtory version!"
msgstr ""
"Enthaltene Geräte konnten auf dem Revolution Pi nicht gefunden werden. "
"Möglicherweise stammt die Konfiguration von einer neueren piCtory Version!"
#: revpiprogram.py:431
msgid "Could not load RAP catalog on Revolution Pi."
msgstr "Konnte RAP Katalog auf dem Revolution Pi nicht laden."
#: revpiprogram.py:437
msgid "The piCtory configuration could not be written on the Revolution Pi."
msgstr ""
"Die piCtory Konfiguration konnte auf dem Revolution Pi nicht geschrieben "
"werden."
#: revpiprogram.py:444
msgid ""
"The piCtroy configuration has been saved successfully. \n"
"An error occurred on piControl reset!"
msgstr ""
"Die piCtroy Konfiguration wurde erfolgreich gespeichert. \n"
"Beim piControl Reset trat allerdings ein Fehler auf!"
#: revpiprogram.py:455
msgid ""
"Are you sure to reset piControl? \n"
"The process image and the piBridge are interrupted !!!"
msgstr ""
"Soll piControlReset wirklich durchgeführt werden? \n"
"Das Prozessabbild und die piBridge werden dann unterbrochen!!!"
#: revpiprogram.py:464
msgid "piControl reset executed successfully"
msgstr "piControl reset wurde erfolgreich ausgeführt"
#: revpiprogram.py:470
msgid "piControl reset could not be executed successfully"
msgstr "piControl Reset konnte nicht erfolgreich durchgeführt werden"
#: revpiprogram.py:484
msgid "Directory to save"
msgstr "Verzeichnis zum speichern"
#: revpiprogram.py:595
msgid "Folder to upload"
msgstr "Verzeichnis zum Hochladen"
#: revpiprogram.py:606
msgid "Upload Zip archive..."
msgstr "Zip Archiv hochladen..."
#: revpiprogram.py:627
msgid "The specified file is not a ZIP archive."
msgstr "Die angegebene Datei ist kein ZIP Archiv."
#: revpiprogram.py:636
msgid "Upload TarGz archiv..."
msgstr "TarGz Archiv hochladen..."
#: revpiprogram.py:658
msgid "The specified file is not a TAR archive."
msgstr "Die angegebene Datei ist kein TAR Archiv."
#: revpiprogram.py:671
msgid "There was an error deleting the files on the Revolution Pi."
msgstr ""
"Beim Löschen der Dateien auf dem Revolution Pi ist ein Fehler aufgetreten."
#: revpiprogram.py:716
msgid "The PLC program was transferred successfully."
msgstr "Das PLC Programm wurde erfolgreich übertragen."
#: revpiprogram.py:726
msgid "There is no piCtory configuration in this archive."
msgstr "Es wurde keine piCtory Konfiguration im Archiv gefunden."
#: revpiprogram.py:746
msgid "The Revolution Pi could not process some parts of the transmission."
msgstr "Der Revoluton Pi konnte Teile der Übertragung nicht verarbeiten."
#: revpiprogram.py:754
msgid "Errors occurred during transmission"
msgstr "Bei der Übertragung traten Fehler auf"
#: revpipycontrol.py:105
msgid "Connections..."
msgstr "Verbindungen..."
#: revpipycontrol.py:108
msgid "Main"
msgstr "Datei"
#: revpipycontrol.py:116
msgid "Visit website..."
msgstr "Webseite besuchen..."
#: revpipycontrol.py:118
msgid "Info..."
msgstr "Info..."
#: revpipycontrol.py:119
msgid "Help"
msgstr "Hilfe"
#: revpipycontrol.py:127
msgid "PLC start"
msgstr "PLC Start"
#: revpipycontrol.py:132
msgid "PLC stop"
msgstr "PLC Stopp"
#: revpipycontrol.py:137
msgid "PLC restart"
msgstr "PLC Neustart"
#: revpipycontrol.py:142
msgid "PLC logs"
msgstr "PLC Logs"
#: revpipycontrol.py:153
msgid "PLC watch mode"
msgstr "PLC watch Modus"
#: revpipycontrol.py:170
msgid "PLC log..."
msgstr "PLC Log..."
#: revpipycontrol.py:172
msgid "PLC options..."
msgstr "PLC Optionen..."
#: revpipycontrol.py:174
msgid "PLC program..."
msgstr "PLC Programm..."
#: revpipycontrol.py:178
msgid "Disconnect"
msgstr "Trennen"
#: revpipycontrol.py:183
msgid "Connect"
msgstr "Verbinden"
#: revpipycontrol.py:236
msgid ""
"The watch mode ist not supported in version {} of RevPiPyLoad on your RevPi! "
"You need at least version 0.4.0. Or the python3-revpimodio module is not "
"installton your RevPi at least version 0.15.0."
msgstr ""
"Der Watch-Modus wird von der RevPiPyLoad Version {} auf dem RevPi nicht "
"unterstützt! Sie benötigen mindestens Version 0.4.0. Oder das python3-"
"revpimodio Modul ist auf dem RevPi nicht in min. Version 0.15.0 installiert."
#: revpipycontrol.py:281
msgid ""
"This version of Logviewer ist not supported in version {} of RevPiPyLoad on "
"your RevPi! You need at least version 0.4.1."
msgstr ""
"Diese Version vom Logbetrachter wird in der RevPiPyLoad Version {} auf Ihrem "
"RevPi nicht unterstützt! Sie benötigen mindestens Version 0.4.1."
#: revpipycontrol.py:299 revpipycontrol.py:325
msgid ""
"XML-RPC access mode in the RevPiPyLoad configuration is too small to access "
"this dialog!"
msgstr ""
"Der XML-RPC Modus ist beim RevPiPyLoad nicht hoch genug eingestellt, um "
"diesen Dialog zu verwenden!"
#: revpipycontrol.py:364
msgid "Can not reach server!"
msgstr "Server ist nicht erreichbar!"
#~ msgid ""
#~ "The watch mode ist not supported in version {} of RevPiPyLoad on your "
#~ "RevPi! You need at least version 0.4.0."
#~ msgstr ""
#~ "Der Watch-Modus wird von der RevPiPyLoad Version {} auf dem RevPi nicht "
#~ "unterstützt! Sie benötigen mindestens Version 0.4.0."
#~ msgid ""
#~ "XML-RPC access mode in the RevPiPyLoad configuration is too small to "
#~ "access this dialog"
#~ msgstr ""
#~ "Der XML-RPC Modus ist beim RevPiPyLoad nicht hoch genug eingestellt, um "
#~ "diesen Dialog zu verwenden!"
#~ msgid "Do you really want to delete the selected connection '{}'"
#~ msgstr "Wollen Sie die ausgewählte Verbindung '{}' wirklich löschen?"
#~ msgid "piControl0 prozess image"
#~ msgstr "piControl0 Prozessabbild"
#~ msgid "piControlReset executed successfully"
#~ msgstr "piControl Reset war erfolgreich"
#~ msgid ""
#~ "XML-RPC access mode in the RevPiPyLoad configuration is to small to "
#~ "access this dialog"
#~ msgstr ""
#~ "Der XML-RPC Modus ist beim RevPiPyLoad nicht hoch genug eingestellt, um "
#~ "diesen Dialog zu verwenden!"
#~ msgid "Quit"
#~ msgstr "Beenden"
#~ msgid "The transfer was successful."
#~ msgstr "Die Übertragung war erfolgreich."
#~ msgid ""
#~ "The transfer of the piCtory configuration and the reset of piControl have "
#~ "been successfully executed"
#~ msgstr ""
#~ "Die Übertragung der piCtory Konfiguration und der Reset von piControl "
#~ "wurden erfolgreich ausgeführt"
#~ msgid "The piCtory configuration was successfully transferred"
#~ msgstr ""
#~ "Die Übertragung der piCtory Konfiguration wurde erfolgreich ausgeführt"
#~ msgid "Given value for Output '{}' is not valid! Reset to '{}'"
#~ msgstr ""
#~ "Angegebener Wert bei Output '{}' ist nicht gültig! Setze auf '{}' zurück"

49
revpipycontrol/mytools.py Normal file
View File

@@ -0,0 +1,49 @@
#
# RevPiPyControl
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
import gettext
import locale
import sys
from os.path import dirname
from os.path import join as pathjoin
def addroot(filename):
u"""Hängt root-dir der Anwendung vor Dateinamen.
Je nach Ausführungsart der Anwendung muss das root-dir über
andere Arten abgerufen werden.
@param filename Datei oder Ordnername
@return root dir
"""
if getattr(sys, "frozen", False):
return pathjoin(dirname(sys.executable), filename)
else:
return pathjoin(dirname(__file__), filename)
def gettrans(proglang=None):
# Sprache auswählen
if proglang is None:
# Autodetect Language or switch to static
proglang = locale.getdefaultlocale()[0]
if proglang is not None and proglang.find("_") >= 0:
proglang = proglang.split('_')[0]
else:
proglang = "en"
# Übersetzungen laden
trans = gettext.translation(
"revpipycontrol",
addroot("locale"),
languages=[proglang],
fallback=True
)
return trans.gettext

View File

@@ -9,216 +9,436 @@
import pickle import pickle
import tkinter import tkinter
from argparse import ArgumentParser import tkinter.messagebox as tkmsg
from concurrent.futures import ThreadPoolExecutor from mytools import gettrans
from time import sleep from threading import Lock
from xmlrpc.client import ServerProxy, Binary, MultiCall from xmlrpc.client import MultiCall
# Übersetzung laden
_ = gettrans()
class RevPiCheckClient(tkinter.Frame): class RevPiCheckClient(tkinter.Frame):
def __init__(self, master, xmlcli): def __init__(self, master, xmlcli, xmlmode=0):
"""Instantiiert MyApp-Klasse.""" """Instantiiert MyApp-Klasse."""
super().__init__(master) super().__init__(master)
self.pack(fill="both", expand=True)
# XML-Daten abrufen
self.xmlmode = xmlmode
self.cli = xmlcli self.cli = xmlcli
self.cli.psstart()
self.lst_devices = self.cli.ps_devices()
self.dict_devices = {v[0]: v[1] for v in self.lst_devices}
self.lst_devices = [d[0] for d in self.lst_devices]
self.dict_inps = pickle.loads(self.cli.ps_inps().data)
self.dict_outs = pickle.loads(self.cli.ps_outs().data)
self.err_workvalues = 0
self.max_errors = 25
self.lst_devices = self.cli.get_devicenames() self.lk = Lock()
self.lst_group = [] self.dict_wins = {}
self.dict_inpvar = {} self.__checkwrite = True
self.dict_outvar = {} self.__lockedvar = None
self.__oldvalue = None
self.autorw = tkinter.BooleanVar() self.autorw = tkinter.BooleanVar()
self.fut_autorw = None self.dowrite = tkinter.BooleanVar()
# Fenster aufbauen # Fenster aufbauen
self._createwidgets() self._createwidgets()
# Aktuelle Werte einlesen # Aktuelle Werte einlesen
self.readvalues() self.refreshvalues()
def _autorw(self): def __chval(self, device, io, event=None):
dict_inp = {} u"""Schreibt neuen Output Wert auf den RevPi."""
dict_out = {} if self.dowrite.get() and self._warnwrite():
with self.lk:
self.validatereturn(
self.cli.ps_setvalue(device, io[0], io[5].get())
)
while self.autorw.get(): # Alles neu einlesen wenn nicht AutoRW aktiv ist
for dev in self.lst_devices: if not self.autorw.get():
try: self.refreshvalues()
dict_out[dev] = [
value[8].get() for value in self.dict_outvar[dev]
]
except:
print("lasse {} aus".format(dev))
dict_inp = self.cli.refreshvalues( self.__lockedvar = None
Binary(pickle.dumps(dict_out, 3))
def __hidewin(self, win, event=None):
u"""Verbergt übergebenes Fenster.
@param win Fenster zum verbergen
@param event Tkinter Event"""
win.withdraw()
def __saveoldvalue(self, event, tkvar):
u"""Speichert bei Keypress aktuellen Wert für wiederherstellung."""
if self.__lockedvar is None:
self.__lockedvar = tkvar
try:
self.__oldvalue = tkvar.get()
except Exception:
pass
def __showwin(self, win):
u"""Zeigt oder verbergt übergebenes Fenster.
@param win Fenster zum anzeigen/verbergen"""
if win.winfo_viewable():
win.withdraw()
else:
win.deiconify()
def __spinboxkey(self, device, io, event=None):
u"""Prüft die Eingabe auf plausibilität.
@param event tkinter Event
@param io IO Liste mit tkinter Variable"""
# io = [name,bytelen,byteaddr,bmk,bitaddress,(tkinter_var)]
try:
newvalue = io[5].get()
# Wertebereich prüfen
if newvalue < 0 or newvalue > self.maxint(io[1]):
raise ValueError("too big")
self.__chval(device, io)
except Exception:
io[5].set(self.__oldvalue)
tkmsg.showerror(
_("Error"),
_("Given value for Output '{}' is not valid! \nReset to ""'{}'"
"").format(self.dict_devices[device], self.__oldvalue),
parent=self.dict_wins[device]
) )
dict_inp = pickle.loads(dict_inp.data)
for dev in dict_inp: # Focus zurücksetzen
for io in self.dict_inpvar[dev]: event.widget.focus_set()
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"))
def _createiogroup(self, device, frame, iotype): def _createiogroup(self, device, frame, iotype):
"""Erstellt IO-Gruppen.""" u"""Erstellt IO-Gruppen.
# IOs generieren
canvas = tkinter.Canvas(frame, borderwidth=0, width=180, heigh=800) @param device Deviceposition
@param frame tkinter Frame
@param iotype 'inp' oder 'out' als str()
"""
# IO-Typen festlegen
if iotype == "inp":
lst_io = self.dict_inps[device]
else:
lst_io = self.dict_outs[device]
# Fensterinhalt aufbauen
calc_heigh = len(lst_io) * 21
canvas = tkinter.Canvas(
frame,
borderwidth=0,
width=180,
heigh=calc_heigh if calc_heigh <= 600 else 600
)
s_frame = tkinter.Frame(canvas) s_frame = tkinter.Frame(canvas)
vsb = tkinter.Scrollbar(frame, orient="vertical", command=canvas.yview) vsb = tkinter.Scrollbar(frame, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set) canvas.configure(yscrollcommand=vsb.set)
# Scrollrad Linux
canvas.bind(
"<ButtonPress-4>",
lambda x: canvas.yview_scroll(-1, "units")
)
canvas.bind(
"<ButtonPress-5>",
lambda x: canvas.yview_scroll(1, "units")
)
vsb.pack(side="right", fill="y") vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True) canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4, 4), window=s_frame, anchor="nw") canvas.create_window((4, 4), window=s_frame, anchor="nw")
s_frame.bind( s_frame.bind(
"<Configure>", lambda event, canvas=canvas: self.onfrmconf(canvas) "<Configure>", lambda event, canvas=canvas: self._onfrmconf(canvas)
) )
# IOs generieren
rowcount = 0 rowcount = 0
for io in self.cli.get_iolist(device, iotype): for io in lst_io:
# io = [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress,tkinter_var] # io = [name,bytelen,byteaddr,bmk,bitaddress,(tkinter_var)]
tkinter.Label(s_frame, text=io[0]).grid( tkinter.Label(s_frame, text=io[0]).grid(
column=0, row=rowcount, sticky="w" column=0, row=rowcount, sticky="w"
) )
if io[7] >= 0: if io[4] >= 0:
var = tkinter.BooleanVar() var = tkinter.BooleanVar()
check = tkinter.Checkbutton(s_frame) 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["state"] = "disabled" if iotype == "inp" else "normal"
check["text"] = "" check["text"] = ""
check["variable"] = var check["variable"] = var
check.grid(column=1, row=rowcount) check.grid(column=1, row=rowcount)
else: else:
var = tkinter.IntVar() var = tkinter.IntVar()
txt = tkinter.Spinbox(s_frame, to=256) txt = tkinter.Spinbox(s_frame, to=self.maxint(io[1]))
txt["state"] = "disabled" if iotype == "inp" else "normal" txt.bind(
txt["width"] = 4 "<Key>",
lambda event, tkvar=var: self.__saveoldvalue(event, tkvar)
)
txt.bind(
"<FocusOut>",
lambda event, device=device, io=io:
self.__spinboxkey(device, io, event)
)
txt["command"] = \
lambda device=device, io=io: self.__chval(device, io)
txt["state"] = "disabled" if iotype == "inp" or \
self.maxint(io[1]) == 0 else "normal"
txt["width"] = 5
txt["textvariable"] = var txt["textvariable"] = var
txt.grid(column=1, row=rowcount) txt.grid(column=1, row=rowcount)
# Steuerelementvariable in IO übernehmen # Steuerelementvariable in IO übernehmen (mutabel)
io.append(var) io.append(var)
if iotype == "inp":
self.dict_inpvar[device].append(io)
elif iotype == "out":
self.dict_outvar[device].append(io)
rowcount += 1 rowcount += 1
def _createwidgets(self): def _createwidgets(self):
"""Erstellt den Fensterinhalt.""" """Erstellt den Fensterinhalt."""
# Hauptfenster cFxPxy53 = {"fill": "x", "padx": 5, "pady": 3}
self.master.wm_title("RevPi Onlineview")
devgrp = tkinter.LabelFrame(self)
devgrp["text"] = _("Devices of RevPi")
devgrp.pack(expand=True, fill="both", side="left")
for dev in self.lst_devices: for dev in self.lst_devices:
# Variablen vorbereiten win = tkinter.Toplevel(self)
self.dict_inpvar[dev] = [] win.wm_title("{} | {}".format(dev, self.dict_devices[dev]))
self.dict_outvar[dev] = [] win.protocol(
"WM_DELETE_WINDOW",
lambda win=win: self.__hidewin(win)
)
win.resizable(False, True)
win.withdraw()
self.dict_wins[dev] = win
# Devicegruppe erstellen # Devicegruppe erstellen
group = tkinter.LabelFrame(self) group = tkinter.LabelFrame(win)
group["text"] = dev group["text"] = self.dict_devices[dev]
group.pack(side="left", fill="both", expand=True) group.pack(side="left", fill="both", expand=True)
self.lst_group.append(group)
for iotype in ["inp", "out"]: for iotype in ["inp", "out"]:
frame = tkinter.Frame(group) frame = tkinter.Frame(group)
frame.pack(side="left", fill="both", expand=True) frame.pack(side="left", fill="both", expand=True)
self._createiogroup(dev, frame, iotype) self._createiogroup(dev, frame, iotype)
# self.btn_update = tkinter.Button(self) # Button erstellen
# self.btn_update["text"] = "UPDATE" btn = tkinter.Button(devgrp)
# self.btn_update["command"] = self._autorw btn["command"] = lambda win=win: self.__showwin(win)
# self.btn_update.pack(anchor="s", side="bottom", fill="x") btn["text"] = "{} | {}".format(dev, self.dict_devices[dev])
btn.pack(**cFxPxy53)
self.btn_write = tkinter.Button(self) # Steuerungsfunktionen
self.btn_write["text"] = "SCHREIBEN" cntgrp = tkinter.LabelFrame(self)
self.btn_write["command"] = self.writevalues cntgrp["text"] = _("Control")
self.btn_write.pack(side="bottom", fill="x") cntgrp.pack(expand=True, fill="both", side="right")
self.btn_read = tkinter.Button(self) self.btn_refresh = tkinter.Button(cntgrp)
self.btn_read["text"] = "LESEN" self.btn_refresh["text"] = _("Read all IOs")
self.btn_refresh["command"] = self.refreshvalues
self.btn_refresh.pack(**cFxPxy53)
self.btn_read = tkinter.Button(cntgrp)
self.btn_read["text"] = _("Read just Inputs")
self.btn_read["command"] = self.readvalues self.btn_read["command"] = self.readvalues
self.btn_read.pack(side="bottom", fill="x") self.btn_read.pack(**cFxPxy53)
check = tkinter.Checkbutton(self) self.btn_write = tkinter.Button(cntgrp)
check["command"] = self.toggleauto self.btn_write["state"] = "normal" if self.xmlmode >= 3 \
check["text"] = "autoupdate" else "disabled"
check["variable"] = self.autorw self.btn_write["text"] = _("Write Outputs")
check.pack(side="bottom") self.btn_write["command"] = self.writevalues
self.btn_write.pack(**cFxPxy53)
def _readvaluesdev(self, device, iotype): self.chk_auto = tkinter.Checkbutton(cntgrp)
"""Ruft alle aktuellen Werte fuer das Device ab.""" self.chk_auto["command"] = self.toggleauto
# Multicall vorbereiten self.chk_auto["text"] = _("Autorefresh values")
mc_values = MultiCall(self.cli) self.chk_auto["variable"] = self.autorw
self.chk_auto.pack(anchor="w")
if iotype == "inp": self.chk_dowrite = tkinter.Checkbutton(cntgrp)
lst_ios = self.dict_inpvar[device] self.chk_dowrite["command"] = self.togglewrite
elif iotype == "out": self.chk_dowrite["state"] = "normal" if self.xmlmode >= 3 \
lst_ios = self.dict_outvar[device] and self.autorw.get() else "disabled"
self.chk_dowrite["text"] = _("Write values to RevPi")
self.chk_dowrite["variable"] = self.dowrite
self.chk_dowrite.pack(anchor="w")
for io in lst_ios: def _onfrmconf(self, canvas):
mc_values.get_iovalue(device, io[0]) u"""Erstellt Fenster in einem Canvas.
@param canvas Canvas in dem Objekte erstellt werden sollen"""
canvas.configure(scrollregion=canvas.bbox("all"))
i = 0 def _warnwrite(self):
for value in mc_values(): u"""Warnung für Benutzer über Schreibfunktion einmal fragen.
value = pickle.loads(value.data) @return True, wenn Warnung einmal mit OK bestätigt wurde"""
if type(value) == bytes: if self.__checkwrite:
value = int.from_bytes(value, byteorder="little") self.__checkwrite = not tkmsg.askokcancel(
_("Warning"),
_("You want to set outputs on the RevPi! Note that these are "
"set IMMEDIATELY!!! \nIf another control program is "
"running on the RevPi, it could interfere and reset the "
"outputs."),
icon=tkmsg.WARNING,
parent=self.master
)
return not self.__checkwrite
lst_ios[i][8].set(value) def _workvalues(self, io_dicts=None, writeout=False):
i += 1 u"""Alle Werte der Inputs und Outputs abrufen.
def _writevaluesdev(self, device): @param io_dicts Arbeit nur für dieses Dict()
"""Sendet Werte der Outputs fuer ein Device.""" @param writeout Änderungen auf RevPi schreiben
# Multicall vorbereiten @return None
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)) # Abfragelisten vorbereiten
if io_dicts is None:
io_dicts = [self.dict_inps, self.dict_outs]
# Multicall ausführen # Werte abrufen
mc_values() with self.lk:
try:
ba_values = bytearray(self.cli.ps_values().data)
self.err_workvalues = 0
except:
if self.autorw.get():
self.err_workvalues += 1
else:
self.err_workvalues = self.max_errors
if self.err_workvalues >= self.max_errors:
self.hideallwindows()
self.pack_forget()
return None
# Multicall zum Schreiben vorbereiten
if writeout:
xmlmc = MultiCall(self.cli)
for dev in self.dict_devices:
# io = [name,bytelen,byteaddr,bmk,bitaddress,(tkinter_var)]
# IO Typ verarbeiten
for iotype in io_dicts:
# ios verarbeiten
for io in iotype[dev]:
# Gesperrte Variable überspringen
if io[5] == self.__lockedvar:
continue
# Bytes umwandeln
int_byte = int.from_bytes(
ba_values[io[2]:io[2] + io[1]], byteorder="little"
)
if io[4] >= 0:
# Bit-IO
new_val = bool(int_byte & 1 << io[4])
if writeout and new_val != io[5].get():
xmlmc.ps_setvalue(dev, io[0], io[5].get())
else:
io[5].set(new_val)
else:
# Byte-IO
if writeout and int_byte != io[5].get():
xmlmc.ps_setvalue(dev, io[0], io[5].get())
else:
io[5].set(int_byte)
# Werte per Multicall schreiben
if writeout:
with self.lk:
self.validatereturn(xmlmc())
def hideallwindows(self):
u"""Versteckt alle Fenster."""
for win in self.dict_wins:
self.dict_wins[win].withdraw()
def maxint(self, bytelen):
u"""Errechnet maximalen int() Wert für Bytes max 22.
@param bytelen Anzahl Bytes
@return int() max oder 0 bei Überschreitung"""
return 0 if bytelen > 22 else 256 ** bytelen - 1
def readvalues(self): def readvalues(self):
"""Alle Werte der Inputs und Outputs abrufen.""" u"""Ruft nur Input Werte von RevPi ab und aktualisiert Fenster."""
# Werte aus Prozessabbild einlesen if not self.autorw.get():
self.cli.readprocimg() self._workvalues([self.dict_inps])
for dev in self.lst_devices: def refreshvalues(self):
self._readvaluesdev(dev, "inp") u"""Ruft alle IO Werte von RevPi ab und aktualisiert Fenster."""
self._readvaluesdev(dev, "out") if not self.autorw.get():
self._workvalues()
def tmr_workvalues(self):
u"""Timer für zyklische Abfrage.
@return None"""
# Verbleibener Timer könnte schon ungültig sein
if not self.autorw.get():
try:
self.chk_auto["state"] = "normal"
except:
pass
return None
self._workvalues()
self.master.after(200, self.tmr_workvalues)
def toggleauto(self): def toggleauto(self):
self.btn_read["state"] = "disabled" if self.autorw.get() else "normal" u"""Schaltet zwischen Autorefresh um und aktualisiert Widgets."""
self.btn_write["state"] = "disabled" if self.autorw.get() else "normal" stateval = "disabled" if self.autorw.get() else "normal"
if self.autorw.get() \ self.btn_refresh["state"] = stateval
and (self.fut_autorw is None or self.fut_autorw.done()): self.btn_read["state"] = stateval
e = ThreadPoolExecutor(max_workers=1) self.btn_write["state"] = stateval if self.xmlmode >= 3 \
self.fut_autorw = e.submit(self._autorw) else "disabled"
self.chk_dowrite["state"] = "normal" if self.xmlmode >= 3 \
and self.autorw.get() else "disabled"
if self.autorw.get():
self.tmr_workvalues()
else:
self.chk_auto["state"] = "disabled"
self.dowrite.set(False)
def togglewrite(self):
u"""Schaltet zwischen DoWrite um und aktiviert Schreibfunktion."""
if self._warnwrite():
self.refreshvalues()
else:
self.dowrite.set(False)
def validatereturn(self, returnlist):
u"""Überprüft die Rückgaben der setvalue Funktion.
@param returnlist list() der xml Rückgabe"""
if type(returnlist[0]) != list:
returnlist = [returnlist]
str_errmsg = ""
for lst_result in returnlist:
# [device, io, status, msg]
if not lst_result[2]:
# Fehlermeldungen erstellen
devicename = self.dict_devices[lst_result[0]]
str_errmsg += _(
"Error set value of device '{}' Output '{}': {} \n"
).format(devicename, lst_result[1], lst_result[3])
if str_errmsg != "":
tkmsg.showerror(_("Error"), str_errmsg)
def writevalues(self): def writevalues(self):
"""Alle Outputs senden.""" u"""Schreibt geänderte Outputs auf den RevPi."""
pass if self._warnwrite() and not self.autorw.get():
#for dev in self.lst_devices: self._workvalues([self.dict_outs], True)
#self._writevaluesdev(dev)
# Werte in Prozessabbild schreiben
#self.cli.writeprocimg()
if __name__ == "__main__":
root = tkinter.Tk()
myapp = RevPiCheckClient(root)
myapp.mainloop()

143
revpipycontrol/revpiinfo.py Normal file
View File

@@ -0,0 +1,143 @@
#
# RevPiPyControl
#
# Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3
#
# -*- coding: utf-8 -*-
import tkinter
import tkinter.font as tkf
import webbrowser
from mytools import gettrans
# Übersetzung laden
_ = gettrans()
class RevPiInfo(tkinter.Frame):
def __init__(self, master, xmlcli, version):
u"""Init RevPiLogfile-Class."""
self.master = master
self.xmlcli = xmlcli
# Systemvariablen
self.version = version
# Fenster bauen
self._createwidgets()
def _checkclose(self, event=None):
u"""Prüft ob Fenster beendet werden soll.
@param event tkinter-Event"""
self.master.destroy()
def _createwidgets(self, extended=False):
u"""Erstellt alle Widgets."""
super().__init__(self.master)
self.master.wm_title(_("RevPi Python PLC info"))
self.master.bind("<KeyPress-Escape>", self._checkclose)
self.master.resizable(False, False)
self.pack(fill="both", expand=True)
# Fonts laden
fntlarge = tkf.Font(size=20, weight="bold")
fntmid = tkf.Font(size=15)
fntbold = tkf.Font(size=10, weight="bold")
# Kopfdaten
lbl = tkinter.Label(self)
lbl["font"] = fntlarge
lbl["text"] = _("RevPi Python PLC - Control")
lbl.pack(pady=5)
lbl = tkinter.Label(self)
lbl["font"] = fntmid
lbl["text"] = _("Version: {}").format(self.version)
lbl.bind(
"<ButtonPress-2>",
lambda event: self._createwidgets(extended=not extended)
)
lbl.pack(pady=5)
# Mittelframe geteilt (links/rechts) ---------------------------------
frame_main = tkinter.Frame(self)
frame_main.pack(anchor="nw", fill="x", pady=5)
# Rows konfigurieren
frame_main.rowconfigure(0, weight=0)
frame_main.rowconfigure(1, weight=1)
frame_main.rowconfigure(2, weight=1)
int_row = 0
cpadnw = {"padx": 4, "pady": 2, "sticky": "nw"}
cpadsw = {"padx": 4, "pady": 2, "sticky": "sw"}
# Linke Seite Mittelframe ----------------
lbl = tkinter.Label(frame_main)
lbl["font"] = fntbold
lbl["text"] = _("RevPiPyLoad version on RevPi:")
lbl.grid(column=0, row=int_row, **cpadnw)
lbl = tkinter.Label(frame_main)
lbl["font"] = fntbold
lbl["text"] = _("not conn.") if self.xmlcli is None \
else self.xmlcli.version()
lbl.grid(column=1, row=int_row, **cpadnw)
int_row += 1 # 1
lbl = tkinter.Label(frame_main)
lbl["justify"] = "left"
lbl["text"] = _(
"\nRevPiModIO, RevPiPyLoad and RevPiPyControl\n"
"are community driven projects. They are all\n"
"free and open source software.\n"
"All of them comes with ABSOLUTELY NO\n"
"WARRANTY, to the extent permitted by \n"
"applicable law.\n"
"\n"
"\n"
"(c) Sven Sager, License: LGPLv3"
)
lbl.grid(column=0, row=int_row, columnspan=2, **cpadnw)
int_row += 1 # 2
lbl = tkinter.Label(frame_main)
lbl.bind("<ButtonPress-1>", self.visitwebsite)
lbl["fg"] = "blue"
lbl["text"] = "https://revpimodio.org/"
lbl.grid(column=0, row=int_row, columnspan=2, **cpadsw)
# int_row += 1 # 3
# Rechte Seite Mittelframe ---------------
# Funktionen der Gegenstelle
if self.xmlcli is not None:
frame_func = tkinter.Frame(frame_main)
txt_xmlfunc = tkinter.Text(frame_func, width=30, height=15)
scr_xmlfunc = tkinter.Scrollbar(frame_func)
if extended:
txt_xmlfunc.insert(tkinter.END, "\n".join(
self.xmlcli.system.listMethods()
))
elif "get_filelist" in self.xmlcli.system.listMethods():
txt_xmlfunc.insert(tkinter.END, "\n".join(
self.xmlcli.get_filelist()
))
txt_xmlfunc["yscrollcommand"] = scr_xmlfunc.set
txt_xmlfunc["state"] = "disabled"
scr_xmlfunc["command"] = txt_xmlfunc.yview
txt_xmlfunc.pack(side="left")
scr_xmlfunc.pack(fill="y", side="right")
if txt_xmlfunc.get(1.0) != "\n":
frame_func.grid(column=3, row=0, rowspan=int_row + 1, **cpadnw)
# Unten Beenden-Button -----------------------------------------------
self.btnapplog = tkinter.Button(self)
self.btnapplog["command"] = self._checkclose
self.btnapplog["text"] = _("Close")
self.btnapplog.pack(fill="x", padx=100)
def visitwebsite(self, event=None):
u"""Öffnet auf dem System einen Webbrowser zur Projektseite."""
webbrowser.open("https://revpimodio.org")

View File

@@ -6,20 +6,39 @@
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import tkinter import tkinter
from mytools import gettrans
# Übersetzung laden
_ = gettrans()
class RevPiLogfile(tkinter.Frame): class RevPiLogfile(tkinter.Frame):
def __init__(self, master, xmlcli): def __init__(self, master, xmlcli):
u"""Init RevPiLogfile-Class."""
super().__init__(master) super().__init__(master)
self.master.bind("<KeyPress-Escape>", self._checkclose)
self.pack(fill="both", expand=True) self.pack(fill="both", expand=True)
self.xmlcli = xmlcli self.xmlcli = xmlcli
# Systemvariablen
self.loadblock = 16384
self.errapp = 0
self.errplc = 0
self.mrkapp = 0
self.mrkplc = 0
# Fenster bauen # Fenster bauen
self._createwidgets() self._createwidgets()
def _checkclose(self, event=None):
u"""Prüft ob Fenster beendet werden soll.
@param event tkinter-Event"""
self.master.destroy()
def _createwidgets(self): def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Logs") u"""Erstellt alle Widgets."""
self.master.wm_title(_("RevPi Python PLC Logs"))
self.rowconfigure(0, weight=0) self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1) self.rowconfigure(1, weight=1)
@@ -32,11 +51,11 @@ class RevPiLogfile(tkinter.Frame):
# PLC Log # PLC Log
self.lblapplog = tkinter.Label(self) self.lblapplog = tkinter.Label(self)
self.lblapplog["text"] = "RevPyPyLoad - Logfile" self.lblapplog["text"] = _("RevPiPyLoad - Logfile")
self.lblapplog.grid(column=0, row=0, sticky="w") self.lblapplog.grid(column=0, row=0, sticky="w")
self.btnapplog = tkinter.Button(self) self.btnapplog = tkinter.Button(self)
self.btnapplog["command"] = self.btn_clearplc self.btnapplog["command"] = self.btn_clearplc
self.btnapplog["text"] = "Clear screen" self.btnapplog["text"] = _("Clear screen")
self.btnapplog.grid(column=1, row=0, sticky="e") self.btnapplog.grid(column=1, row=0, sticky="e")
self.plclog = tkinter.Text(self) self.plclog = tkinter.Text(self)
self.plcscr = tkinter.Scrollbar(self) self.plcscr = tkinter.Scrollbar(self)
@@ -47,11 +66,11 @@ class RevPiLogfile(tkinter.Frame):
# APP Log # APP Log
self.lblapplog = tkinter.Label(self) self.lblapplog = tkinter.Label(self)
self.lblapplog["text"] = "Python PLC program - Logfile" self.lblapplog["text"] = _("Python PLC program - Logfile")
self.lblapplog.grid(column=3, row=0, sticky="w") self.lblapplog.grid(column=3, row=0, sticky="w")
self.btnapplog = tkinter.Button(self) self.btnapplog = tkinter.Button(self)
self.btnapplog["command"] = self.btn_clearapp self.btnapplog["command"] = self.btn_clearapp
self.btnapplog["text"] = "Clear screen" self.btnapplog["text"] = _("Clear screen")
self.btnapplog.grid(column=4, row=0, sticky="e") self.btnapplog.grid(column=4, row=0, sticky="e")
self.applog = tkinter.Text(self) self.applog = tkinter.Text(self)
self.appscr = tkinter.Scrollbar(self) self.appscr = tkinter.Scrollbar(self)
@@ -60,47 +79,92 @@ class RevPiLogfile(tkinter.Frame):
self.applog["yscrollcommand"] = self.appscr.set self.applog["yscrollcommand"] = self.appscr.set
self.appscr["command"] = self.applog.yview self.appscr["command"] = self.applog.yview
self.get_applog() # Logtimer zum Laden starten
self.get_plclog() self.get_applog(full=True)
self.get_plclog(full=True)
# Timer zum nachladen aktivieren
self.master.after(1000, self.get_applines)
self.master.after(1000, self.get_plclines)
def btn_clearapp(self): def btn_clearapp(self):
u"""Leert die Logliste der App."""
self.applog.delete(1.0, tkinter.END) self.applog.delete(1.0, tkinter.END)
def btn_clearplc(self): def btn_clearplc(self):
u"""Leert die Logliste des PLC."""
self.plclog.delete(1.0, tkinter.END) self.plclog.delete(1.0, tkinter.END)
def get_applines(self): def get_applog(self, full=False):
roll = self.applog.yview()[1] == 1.0 u"""Ruft App Logbuch ab.
@param full Ganzes Logbuch laden"""
# Logs abrufen und letzte Position merken
try: try:
for line in self.xmlcli.get_applines(): self.mrkapp = self._load_log(
self.applog.insert(tkinter.END, line) self.applog, self.xmlcli.load_applog, self.mrkapp, full
)
self.errapp = 0
except: except:
pass self.errapp += 1
if roll:
self.applog.see(tkinter.END)
self.master.after(1000, self.get_applines)
def get_applog(self): # Timer neu starten
self.applog.delete(1.0, tkinter.END) self.master.after(1000, self.get_applog)
self.applog.insert(1.0, self.xmlcli.get_applog())
self.applog.see(tkinter.END)
def get_plclines(self): def get_plclog(self, full=False):
roll = self.plclog.yview()[1] == 1.0 u"""Ruft PLC Logbuch ab.
@param full Ganzes Logbuch laden"""
# Logs abrufen und letzte Position merken
try: try:
for line in self.xmlcli.get_plclines(): self.mrkplc = self._load_log(
self.plclog.insert(tkinter.END, line) self.plclog, self.xmlcli.load_plclog, self.mrkplc, full
)
self.errplc = 0
except: except:
pass self.errplc += 1
if roll:
self.plclog.see(tkinter.END)
self.master.after(1000, self.get_plclines)
def get_plclog(self): # Timer neu starten
self.plclog.delete(1.0, tkinter.END) self.master.after(1000, self.get_plclog)
self.plclog.insert(1.0, self.xmlcli.get_plclog())
self.plclog.see(tkinter.END) def _load_log(self, textwidget, xmlcall, startposition, full):
u"""Läd die angegebenen Logfiles herunter.
@param textwidget Widget in das Logs eingefügt werden sollen
@param xmlcall xmlrpc Funktion zum Abrufen der Logdaten
@param startposition Startposition ab der Logdaten kommen sollen
@param full Komplettes Logbuch laden
@return Ende der Datei (neue Startposition)
"""
roll = textwidget.yview()[1] == 1.0
startposition = 0 if full else startposition
logbytes = b''
while True:
# Datenblock vom XML-RPC Server holen
bytebuff = xmlcall(startposition, self.loadblock).data
logbytes += bytebuff
startposition += len(bytebuff)
# Prüfen ob alle Daten übertragen wurden
if len(bytebuff) < self.loadblock:
break
if full:
textwidget.delete(1.0, tkinter.END)
if bytebuff == b'\x16': # 
# Kein Zugriff auf Logdatei
textwidget.delete(1.0, tkinter.END)
textwidget.insert(
tkinter.END, _("Can not access log file on the RevPi")
)
elif bytebuff == b'\x19': # 
# Logdatei neu begonnen
startposition = 0
else:
# Text in Widget übernehmen
textwidget.insert(tkinter.END, logbytes.decode("utf-8"))
# Automatisch ans Ende rollen
if roll or full:
textwidget.see(tkinter.END)
return startposition

View File

@@ -7,35 +7,84 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import tkinter import tkinter
import tkinter.messagebox as tkmsg import tkinter.messagebox as tkmsg
from mytools import gettrans
# Übersetzung laden
_ = gettrans()
class RevPiOption(tkinter.Frame): class RevPiOption(tkinter.Frame):
def __init__(self, master, xmlcli, xmlmode): def __init__(self, master, xmlcli):
if xmlmode < 2: u"""Init RevPiOption-Class.
@return None"""
try:
self.dc = xmlcli.get_config()
except:
self.dc = None
return None return None
super().__init__(master) super().__init__(master)
self.master.bind("<KeyPress-Escape>", self._checkclose)
self.master.protocol("WM_DELETE_WINDOW", self._checkclose)
self.pack(expand=True, fill="both") self.pack(expand=True, fill="both")
self.xmlcli = xmlcli self.xmlcli = xmlcli
self.xmlmode = xmlmode self.mrk_var_xmlmod2 = False
self.xmlstate = "normal" if xmlmode == 3 else "disabled" self.mrk_var_xmlmod3 = False
self.mrk_xmlmodask = False
self.dorestart = False
# Fenster bauen # Fenster bauen
self._createwidgets() self._createwidgets()
self._loadappdata() self._loadappdata()
def _changesdone(self):
u"""Prüft ob sich die Einstellungen geändert haben.
@return True, wenn min. eine Einstellung geändert wurde"""
return (
self.var_start.get() != self.dc.get("autostart", "1")
or self.var_reload.get() != self.dc.get("autoreload", "1")
or self.var_zexit.get() != self.dc.get("zeroonexit", "0")
or self.var_zerr.get() != self.dc.get("zeroonerror", "0")
or self.var_startpy.get() != self.dc.get("plcprogram", "none.py")
or self.var_startargs.get() != self.dc.get("plcarguments", "")
or self.var_pythonver.get() != self.dc.get("pythonversion", "3")
or self.var_slave.get() != self.dc.get("plcslave", "0")
or self.var_xmlon.get() != (self.dc.get("xmlrpc", 0) >= 1)
or self.var_xmlmod2.get() != (self.dc.get("xmlrpc", 0) >= 2)
or self.var_xmlmod3.get() != (self.dc.get("xmlrpc", 0) >= 3)
or self.var_xmlport.get() != self.dc.get("xmlrpcport", "55123")
)
def _checkclose(self, event=None):
u"""Prüft ob Fenster beendet werden soll.
@param event tkinter-Event"""
ask = True
if self._changesdone():
ask = tkmsg.askyesno(
_("Question"),
_("Do you really want to quit? \nUnsaved changes will "
"be lost"),
parent=self.master, default="no"
)
if ask:
self.master.destroy()
def _createwidgets(self): def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Options") u"""Erstellt Widgets."""
self.master.wm_title(_("RevPi Python PLC Options"))
self.master.wm_resizable(width=False, height=False) self.master.wm_resizable(width=False, height=False)
xmlstate = "normal" if self.dc["xmlrpc"] >= 3 else "disabled"
cpadw = {"padx": 4, "pady": 2, "sticky": "w"} cpadw = {"padx": 4, "pady": 2, "sticky": "w"}
cpadwe = {"padx": 4, "pady": 2, "sticky": "we"} cpadwe = {"padx": 4, "pady": 2, "sticky": "we"}
# Gruppe Start/Stop # Gruppe Start/Stop
stst = tkinter.LabelFrame(self) stst = tkinter.LabelFrame(self)
stst["text"] = "Start / Stopp Verhalten" stst["text"] = _("Start / Stop behavior")
stst.grid(columnspan=2, pady=2, sticky="we") stst.grid(columnspan=2, pady=2, sticky="we")
self.var_start = tkinter.BooleanVar(stst) self.var_start = tkinter.BooleanVar(stst)
@@ -44,34 +93,36 @@ class RevPiOption(tkinter.Frame):
self.var_zerr = tkinter.BooleanVar(stst) self.var_zerr = tkinter.BooleanVar(stst)
ckb_start = tkinter.Checkbutton(stst) ckb_start = tkinter.Checkbutton(stst)
ckb_start["text"] = "Programm automatisch starten" ckb_start["text"] = _("Start program automatically")
ckb_start["state"] = self.xmlstate ckb_start["state"] = xmlstate
ckb_start["variable"] = self.var_start ckb_start["variable"] = self.var_start
ckb_start.grid(**cpadw) ckb_start.grid(**cpadw)
ckb_reload = tkinter.Checkbutton(stst) ckb_reload = tkinter.Checkbutton(stst)
ckb_reload["text"] = "Programm nach Beenden neu starten" ckb_reload["text"] = _("Restart program after exit")
ckb_reload["state"] = self.xmlstate ckb_reload["state"] = xmlstate
ckb_reload["variable"] = self.var_reload ckb_reload["variable"] = self.var_reload
ckb_reload.grid(**cpadw) ckb_reload.grid(**cpadw)
ckb_zexit = tkinter.Checkbutton(stst, justify="left") ckb_zexit = tkinter.Checkbutton(stst, justify="left")
ckb_zexit["state"] = self.xmlstate ckb_zexit["state"] = xmlstate
ckb_zexit["text"] = "Prozessabbild auf NULL setzen, wenn " \ ckb_zexit["text"] = _(
"Programm\nerfolgreich beendet wird" "Set process image to NULL if program\n"
"terminates successfully")
ckb_zexit["variable"] = self.var_zexit ckb_zexit["variable"] = self.var_zexit
ckb_zexit.grid(**cpadw) ckb_zexit.grid(**cpadw)
ckb_zerr = tkinter.Checkbutton(stst, justify="left") ckb_zerr = tkinter.Checkbutton(stst, justify="left")
ckb_zerr["state"] = self.xmlstate ckb_zerr["state"] = xmlstate
ckb_zerr["text"] = "Prozessabbild auf NULL setzen, wenn " \ ckb_zerr["text"] = _(
"Programm\ndurch Absturz beendet wird" "Set process image to NULL if program\n"
"terminates with errors")
ckb_zerr["variable"] = self.var_zerr ckb_zerr["variable"] = self.var_zerr
ckb_zerr.grid(**cpadw) ckb_zerr.grid(**cpadw)
# Gruppe Programm # Gruppe Programm
prog = tkinter.LabelFrame(self) prog = tkinter.LabelFrame(self)
prog["text"] = "PLC Programm" prog["text"] = _("PLC program")
prog.grid(columnspan=2, pady=2, sticky="we") prog.grid(columnspan=2, pady=2, sticky="we")
self.var_pythonver = tkinter.IntVar(prog) self.var_pythonver = tkinter.IntVar(prog)
@@ -82,24 +133,24 @@ class RevPiOption(tkinter.Frame):
self.var_pythonver.set(3) self.var_pythonver.set(3)
lbl = tkinter.Label(prog) lbl = tkinter.Label(prog)
lbl["text"] = "Python Version" lbl["text"] = _("Python version")
lbl.grid(columnspan=2, row=0, **cpadw) lbl.grid(columnspan=2, row=0, **cpadw)
rbn = tkinter.Radiobutton(prog) rbn = tkinter.Radiobutton(prog)
rbn["state"] = self.xmlstate rbn["state"] = xmlstate
rbn["text"] = "Python2" rbn["text"] = "Python2"
rbn["value"] = 2 rbn["value"] = 2
rbn["variable"] = self.var_pythonver rbn["variable"] = self.var_pythonver
rbn.grid(column=0, row=1, **cpadw) rbn.grid(column=0, row=1, **cpadw)
rbn = tkinter.Radiobutton(prog) rbn = tkinter.Radiobutton(prog)
rbn["state"] = self.xmlstate rbn["state"] = xmlstate
rbn["text"] = "Python3" rbn["text"] = "Python3"
rbn["value"] = 3 rbn["value"] = 3
rbn["variable"] = self.var_pythonver rbn["variable"] = self.var_pythonver
rbn.grid(column=1, row=1, **cpadw) rbn.grid(column=1, row=1, **cpadw)
lbl = tkinter.Label(prog) lbl = tkinter.Label(prog)
lbl["text"] = "Python PLC Programname" lbl["text"] = _("Python PLC program name")
lbl.grid(columnspan=2, **cpadw) lbl.grid(columnspan=2, **cpadw)
lst = self.xmlcli.get_filelist() lst = self.xmlcli.get_filelist()
@@ -107,11 +158,11 @@ class RevPiOption(tkinter.Frame):
lst.append("none") lst.append("none")
opt_startpy = tkinter.OptionMenu( opt_startpy = tkinter.OptionMenu(
prog, self.var_startpy, *lst) prog, self.var_startpy, *lst)
opt_startpy["state"] = self.xmlstate opt_startpy["state"] = xmlstate
opt_startpy.grid(columnspan=2, **cpadwe) opt_startpy.grid(columnspan=2, **cpadwe)
lbl = tkinter.Label(prog) lbl = tkinter.Label(prog)
lbl["text"] = "Programm Argumente" lbl["text"] = _("Program arguments")
lbl.grid(columnspan=2, **cpadw) lbl.grid(columnspan=2, **cpadw)
txt = tkinter.Entry(prog) txt = tkinter.Entry(prog)
@@ -119,15 +170,15 @@ class RevPiOption(tkinter.Frame):
txt.grid(columnspan=2, **cpadw) txt.grid(columnspan=2, **cpadw)
ckb_slave = tkinter.Checkbutton(prog, justify="left") ckb_slave = tkinter.Checkbutton(prog, justify="left")
ckb_slave["state"] = self.xmlstate ckb_slave["state"] = xmlstate
ckb_slave["text"] = "RevPi als PLC-Slave verwenden" ckb_slave["text"] = _("Use RevPi as PLC-Slave")
ckb_slave["state"] = "disabled" ckb_slave["state"] = "disabled"
ckb_slave["variable"] = self.var_slave ckb_slave["variable"] = self.var_slave
ckb_slave.grid(columnspan=2, **cpadw) ckb_slave.grid(columnspan=2, **cpadw)
# Gruppe XMLRPC # Gruppe XMLRPC
xmlrpc = tkinter.LabelFrame(self) xmlrpc = tkinter.LabelFrame(self)
xmlrpc["text"] = "XML-RPC Server" xmlrpc["text"] = _("XML-RPC server")
xmlrpc.grid(columnspan=2, pady=2, sticky="we") xmlrpc.grid(columnspan=2, pady=2, sticky="we")
self.var_xmlon = tkinter.BooleanVar(xmlrpc) self.var_xmlon = tkinter.BooleanVar(xmlrpc)
@@ -138,124 +189,161 @@ class RevPiOption(tkinter.Frame):
ckb_xmlon = tkinter.Checkbutton(xmlrpc) ckb_xmlon = tkinter.Checkbutton(xmlrpc)
ckb_xmlon["command"] = self.askxmlon ckb_xmlon["command"] = self.askxmlon
ckb_xmlon["state"] = self.xmlstate ckb_xmlon["state"] = xmlstate
ckb_xmlon["text"] = "XML-RPC Server aktiv auf RevPi" ckb_xmlon["text"] = _("Activate XML-RPC server on RevPi")
ckb_xmlon["variable"] = self.var_xmlon ckb_xmlon["variable"] = self.var_xmlon
ckb_xmlon.grid(**cpadw) ckb_xmlon.grid(**cpadw)
self.ckb_xmlmod2 = tkinter.Checkbutton(xmlrpc, justify="left") self.ckb_xmlmod2 = tkinter.Checkbutton(xmlrpc, justify="left")
self.ckb_xmlmod2["command"] = self.xmlmods self.ckb_xmlmod2["command"] = self.xmlmod2_tail
self.ckb_xmlmod2["state"] = self.xmlstate self.ckb_xmlmod2["state"] = xmlstate
self.ckb_xmlmod2["text"] = \ self.ckb_xmlmod2["text"] = \
"Download von piCtory Konfiguration und\nPLC Programm zulassen" _("Allow download of piCtory configuration and\nPLC programm")
self.ckb_xmlmod2["variable"] = self.var_xmlmod2 self.ckb_xmlmod2["variable"] = self.var_xmlmod2
self.ckb_xmlmod2.grid(**cpadw) self.ckb_xmlmod2.grid(**cpadw)
self.ckb_xmlmod3 = tkinter.Checkbutton(xmlrpc, justify="left") self.ckb_xmlmod3 = tkinter.Checkbutton(xmlrpc, justify="left")
self.ckb_xmlmod3["state"] = self.xmlstate self.ckb_xmlmod3["state"] = xmlstate
self.ckb_xmlmod3["text"] = \ self.ckb_xmlmod3["text"] = \
"Upload von piCtory Konfiguration und\nPLC Programm zualssen" _("Allow upload of piCtory configuration and\nPLC programm")
self.ckb_xmlmod3["variable"] = self.var_xmlmod3 self.ckb_xmlmod3["variable"] = self.var_xmlmod3
self.ckb_xmlmod3.grid(**cpadw) self.ckb_xmlmod3.grid(**cpadw)
lbl = tkinter.Label(xmlrpc) lbl = tkinter.Label(xmlrpc)
lbl["text"] = "XML-RPC Serverport" lbl["text"] = _("XML-RPC server port")
lbl.grid(**cpadw) lbl.grid(**cpadw)
spb_xmlport = tkinter.Spinbox(xmlrpc) spb_xmlport = tkinter.Spinbox(xmlrpc)
spb_xmlport["to"] = 65535 spb_xmlport["to"] = 65535
spb_xmlport["from"] = 1024 spb_xmlport["from"] = 1024
spb_xmlport["state"] = self.xmlstate spb_xmlport["state"] = xmlstate
spb_xmlport["textvariable"] = self.var_xmlport spb_xmlport["textvariable"] = self.var_xmlport
spb_xmlport.grid(**cpadwe) spb_xmlport.grid(**cpadwe)
# Buttons # Buttons
btn_save = tkinter.Button(self) btn_save = tkinter.Button(self)
btn_save["command"] = self._setappdata btn_save["command"] = self._setappdata
btn_save["state"] = self.xmlstate btn_save["state"] = xmlstate
btn_save["text"] = "Speichern" btn_save["text"] = _("Save")
btn_save.grid(column=0, row=3) btn_save.grid(column=0, row=3)
btn_close = tkinter.Button(self) btn_close = tkinter.Button(self)
btn_close["command"] = self.master.destroy btn_close["command"] = self._checkclose
btn_close["text"] = "Schließen" btn_close["text"] = _("Close")
btn_close.grid(column=1, row=3) btn_close.grid(column=1, row=3)
def _loadappdata(self): def _loadappdata(self, refresh=False):
dc = self.xmlcli.get_config() u"""Läd aktuelle Einstellungen vom RevPi.
@param refresh Wenn True, werden Einstellungen heruntergeladen."""
if refresh:
self.dc = self.xmlcli.get_config()
self.var_start.set(dc.get("autostart", "1")) self.var_start.set(self.dc.get("autostart", "1"))
self.var_reload.set(dc.get("autoreload", "1")) self.var_reload.set(self.dc.get("autoreload", "1"))
self.var_zexit.set(dc.get("zeroonexit", "0")) self.var_zexit.set(self.dc.get("zeroonexit", "0"))
self.var_zerr.set(dc.get("zeroonerror", "0")) self.var_zerr.set(self.dc.get("zeroonerror", "0"))
self.var_startpy.set(dc.get("plcprogram", "none.py")) self.var_startpy.set(self.dc.get("plcprogram", "none.py"))
self.var_startargs.set(dc.get("plcarguments", "")) self.var_startargs.set(self.dc.get("plcarguments", ""))
self.var_pythonver.set(dc.get("pythonversion", "3")) self.var_pythonver.set(self.dc.get("pythonversion", "3"))
self.var_slave.set(dc.get("plcslave", "0")) self.var_slave.set(self.dc.get("plcslave", "0"))
self.var_xmlon.set(dc.get("xmlrpc", 0) >= 1) self.var_xmlon.set(self.dc.get("xmlrpc", 0) >= 1)
self.var_xmlmod2.set(dc.get("xmlrpc", 0) >= 2) self.var_xmlmod2.set(self.dc.get("xmlrpc", 0) >= 2)
self.var_xmlmod3.set(dc.get("xmlrpc", 0) >= 3) self.mrk_var_xmlmod2 = self.var_xmlmod2.get()
self.var_xmlmod3.set(self.dc.get("xmlrpc", 0) >= 3)
self.mrk_var_xmlmod3 = self.var_xmlmod3.get()
self.var_xmlport.set(dc.get("xmlrpcport", "55123")) self.var_xmlport.set(self.dc.get("xmlrpcport", "55123"))
def _setappdata(self): def _setappdata(self):
dc = {} u"""Speichert geänderte Einstellungen auf RevPi.
dc["autostart"] = int(self.var_start.get()) @return None"""
dc["autoreload"] = int(self.var_reload.get())
dc["zeroonexit"] = int(self.var_zexit.get())
dc["zeroonerror"] = int(self.var_zerr.get())
dc["plcprogram"] = self.var_startpy.get() if not self._changesdone():
dc["plcarguments"] = self.var_startargs.get() tkmsg.showinfo(
dc["pythonversion"] = self.var_pythonver.get() _("Information"),
dc["plcslave"] = int(self.var_slave.get()) _("You have not made any changes to save."),
)
dc["xmlrpc"] = 0 self._checkclose()
if self.var_xmlon.get(): return None
dc["xmlrpc"] += 1
if self.var_xmlmod2.get():
dc["xmlrpc"] += 1
if self.var_xmlmod3.get():
dc["xmlrpc"] += 1
dc["xmlrpcport"] = self.var_xmlport.get()
self.xmlmode = dc["xmlrpc"]
ask = tkmsg.askyesnocancel( ask = tkmsg.askyesnocancel(
"Frage", "Die Einstellungen werden jetzt auf dem Revolution Pi " _("Question"),
"gespeichert. \n\nSollen die neuen Einstellungen sofort in Kraft " _("The settings are now saved on the Revolution Pi. \n\n"
"treten? \nDies bedeutet einen Neustart des Dienstes und des ggf. " "Should the new settings take effect immediately? \nThis "
"laufenden PLC-Programms!", parent=self.master "means a restart of the service and the PLC program!"),
parent=self.master
) )
if ask is not None: if ask is not None:
if self.xmlcli.set_config(dc, ask): self.dc["autostart"] = int(self.var_start.get())
self.dc["autoreload"] = int(self.var_reload.get())
self.dc["zeroonexit"] = int(self.var_zexit.get())
self.dc["zeroonerror"] = int(self.var_zerr.get())
self.dc["plcprogram"] = self.var_startpy.get()
self.dc["plcarguments"] = self.var_startargs.get()
self.dc["pythonversion"] = self.var_pythonver.get()
self.dc["plcslave"] = int(self.var_slave.get())
self.dc["xmlrpc"] = 0
if self.var_xmlon.get():
self.dc["xmlrpc"] += 1
if self.var_xmlmod2.get():
self.dc["xmlrpc"] += 1
if self.var_xmlmod3.get():
self.dc["xmlrpc"] += 1
self.dc["xmlrpcport"] = self.var_xmlport.get()
if self.xmlcli.set_config(self.dc, ask):
tkmsg.showinfo( tkmsg.showinfo(
"Information", "Einstellungen gespeichert.", _("Information"),
_("Settings saved"),
parent=self.master parent=self.master
) )
self.dorestart = ask
self._checkclose()
else: else:
tkmsg.showerror( tkmsg.showerror(
"Fehler", "Die Einstellungen konnten nicht gesichert" _("Error"),
"werden. Dies kann passieren, wenn Werte falsch sind!", _("The settings could not be saved. This can happen if "
"values are wrong!"),
parent=self.master parent=self.master
) )
def askxmlon(self): def askxmlon(self):
if not self.var_xmlon.get(): u"""Fragt Nuter, ob wirklicht abgeschaltet werden soll."""
ask = tkmsg.askyesno( if not (self.var_xmlon.get() or self.mrk_xmlmodask):
"Frage", "Soll der XML-RPC Server wirklich beendet werden? " self.mrk_xmlmodask = tkmsg.askyesno(
"Sie können dann NICHT mehr mit diesem Programm auf den " _("Question"),
"Revolution Pi zugreifen.", parent=self.master _("Are you sure you want to deactivate the XML-RPC server? "
"You will NOT be able to access the Revolution Pi with "
"this program."),
parent=self.master
) )
if not ask: if not self.mrk_xmlmodask:
self.var_xmlon.set(True) self.var_xmlon.set(True)
self.xmlmods() self.xmlmod_tail()
def xmlmods(self): def xmlmod_tail(self):
self.ckb_xmlmod2["state"] = \ u"""Passt XML-Optionszugriff an."""
"normal" if self.var_xmlon.get() else "disabled" if self.var_xmlon.get():
self.ckb_xmlmod3["state"] = \ self.var_xmlmod2.set(self.mrk_var_xmlmod2)
"normal" if self.var_xmlmod2.get() else "disabled" self.ckb_xmlmod2["state"] = "normal"
else:
self.mrk_var_xmlmod2 = self.var_xmlmod2.get()
self.var_xmlmod2.set(False)
self.ckb_xmlmod2["state"] = "disabled"
self.xmlmod2_tail()
def xmlmod2_tail(self):
u"""Passt XML-Optionszugriff an."""
if self.var_xmlmod2.get():
self.var_xmlmod3.set(self.mrk_var_xmlmod3)
self.ckb_xmlmod3["state"] = "normal"
else:
self.mrk_var_xmlmod3 = self.var_xmlmod3.get()
self.var_xmlmod3.set(False)
self.ckb_xmlmod3["state"] = "disabled"

View File

@@ -9,10 +9,14 @@ import os.path
import pickle import pickle
import tkinter import tkinter
import tkinter.messagebox as tkmsg import tkinter.messagebox as tkmsg
from mytools import gettrans
from os import environ from os import environ
from os import makedirs from os import makedirs
from sys import platform from sys import platform
# Übersetzungen laden
_ = gettrans()
# Systemwerte # Systemwerte
if platform == "linux": if platform == "linux":
homedir = environ["HOME"] homedir = environ["HOME"]
@@ -22,6 +26,8 @@ savefile = os.path.join(homedir, ".revpipyplc", "connections.dat")
def get_connections(): def get_connections():
u"""Verbindungen aus Datei laden.
@return dict() mit Verbindungen"""
if os.path.exists(savefile): if os.path.exists(savefile):
fh = open(savefile, "rb") fh = open(savefile, "rb")
connections = pickle.load(fh) connections = pickle.load(fh)
@@ -33,21 +39,41 @@ def get_connections():
class RevPiPlcList(tkinter.Frame): class RevPiPlcList(tkinter.Frame):
def __init__(self, master): def __init__(self, master):
u"""Init RevPiPlcList-class.
@param master tkinter master"""
super().__init__(master) super().__init__(master)
self.master.bind("<KeyPress-Escape>", self._checkclose)
self.pack() self.pack()
self.changes = False self.changes = False
# Daten laden # Daten laden
self._connections = {} self._connections = get_connections()
# Fenster bauen # Fenster bauen
self._createwidgets() self._createwidgets()
self._loadappdata() self.build_listconn()
def _checkclose(self, event=None):
u"""Prüft ob Fenster beendet werden soll.
@param event tkinter-Event"""
ask = True
if self.changes:
ask = tkmsg.askyesno(
_("Question"),
_("Do you really want to quit? \nUnsaved changes will "
"be lost"),
parent=self.master
)
if ask:
self.master.destroy()
def _createwidgets(self): def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Connections") u"""Erstellt alle Widgets."""
self.master.wm_title(_("RevPi Python PLC connections"))
self.master.wm_resizable(width=False, height=False) self.master.wm_resizable(width=False, height=False)
self.master.protocol("WM_DELETE_WINDOW", self._checkclose)
# Listbox mit vorhandenen Verbindungen # Listbox mit vorhandenen Verbindungen
self.scr_conn = tkinter.Scrollbar(self) self.scr_conn = tkinter.Scrollbar(self)
@@ -65,14 +91,14 @@ class RevPiPlcList(tkinter.Frame):
self.var_port.set("55123") self.var_port.set("55123")
# Eingabefelder für Adresse und Namen # Eingabefelder für Adresse und Namen
tkinter.Label(self, text="Name").grid( tkinter.Label(self, text=_("Name")).grid(
column=2, row=0, sticky="wn", padx=5, pady=5) column=2, row=0, sticky="wn", padx=5, pady=5)
self.txt_name = tkinter.Entry(self, textvariable=self.var_name) self.txt_name = tkinter.Entry(self, textvariable=self.var_name)
self.txt_name.bind("<KeyRelease>", self.evt_keypress) self.txt_name.bind("<KeyRelease>", self.evt_keypress)
self.txt_name.grid( self.txt_name.grid(
column=3, row=0, columnspan=3, sticky="n", padx=5, pady=5) column=3, row=0, columnspan=3, sticky="n", padx=5, pady=5)
tkinter.Label(self, text="IP-Adresse").grid( tkinter.Label(self, text=_("IP address")).grid(
column=2, row=1, sticky="wn", padx=5, pady=5 column=2, row=1, sticky="wn", padx=5, pady=5
) )
self.txt_address = tkinter.Entry(self, textvariable=self.var_address) self.txt_address = tkinter.Entry(self, textvariable=self.var_address)
@@ -80,7 +106,7 @@ class RevPiPlcList(tkinter.Frame):
self.txt_address.grid( self.txt_address.grid(
column=3, row=1, columnspan=3, sticky="n", padx=5, pady=5) column=3, row=1, columnspan=3, sticky="n", padx=5, pady=5)
tkinter.Label(self, text="Port").grid( tkinter.Label(self, text=_("Port")).grid(
column=2, row=2, sticky="wn", padx=5, pady=5) column=2, row=2, sticky="wn", padx=5, pady=5)
self.txt_port = tkinter.Entry(self, textvariable=self.var_port) self.txt_port = tkinter.Entry(self, textvariable=self.var_port)
self.txt_port.bind("<KeyRelease>", self.evt_keypress) self.txt_port.bind("<KeyRelease>", self.evt_keypress)
@@ -89,32 +115,28 @@ class RevPiPlcList(tkinter.Frame):
# Listenbutton # Listenbutton
self.btn_new = tkinter.Button( self.btn_new = tkinter.Button(
self, text="Neu", command=self.evt_btnnew) self, text=_("New"), command=self.evt_btnnew)
self.btn_new.grid(column=2, row=3, sticky="s") self.btn_new.grid(column=2, row=3, sticky="s")
self.btn_add = tkinter.Button( self.btn_add = tkinter.Button(
self, text="Übernehmen", command=self.evt_btnadd, self, text=_("Apply"), command=self.evt_btnadd,
state="disabled") state="disabled")
self.btn_add.grid(column=3, row=3, sticky="s") self.btn_add.grid(column=3, row=3, sticky="s")
self.btn_remove = tkinter.Button( self.btn_remove = tkinter.Button(
self, text="Entfernen", command=self.evt_btnremove, self, text=_("Remove"), command=self.evt_btnremove,
state="disabled") state="disabled")
self.btn_remove.grid(column=4, row=3, sticky="s") self.btn_remove.grid(column=4, row=3, sticky="s")
# Fensterbuttons # Fensterbuttons
self.btn_save = tkinter.Button( self.btn_save = tkinter.Button(
self, text="Speichern", command=self.evt_btnsave) self, text=_("Save"), command=self.evt_btnsave)
self.btn_save.grid(column=3, row=9, sticky="se") self.btn_save.grid(column=3, row=9, sticky="se")
self.btn_close = tkinter.Button( self.btn_close = tkinter.Button(
self, text="Schließen", command=self.evt_btnclose) self, text=_("Close"), command=self._checkclose)
self.btn_close.grid(column=4, row=9, sticky="se") 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): def _saveappdata(self):
u"""Speichert Verbindungen im home Dir.
@return True, bei erfolgreicher Verarbeitung"""
try: try:
makedirs(os.path.dirname(savefile), exist_ok=True) makedirs(os.path.dirname(savefile), exist_ok=True)
fh = open(savefile, "wb") fh = open(savefile, "wb")
@@ -125,11 +147,13 @@ class RevPiPlcList(tkinter.Frame):
return True return True
def build_listconn(self): def build_listconn(self):
u"""Füllt Verbindungsliste."""
self.list_conn.delete(0, "end") self.list_conn.delete(0, "end")
lst_conns = sorted(self._connections.keys(), key=lambda x: x.lower()) lst_conns = sorted(self._connections.keys(), key=lambda x: x.lower())
self.list_conn.insert("end", *lst_conns) self.list_conn.insert("end", *lst_conns)
def evt_btnadd(self): def evt_btnadd(self):
u"""Verbindungseinstellungen übernehmen."""
# TODO: Daten prüfen # TODO: Daten prüfen
self._connections[self.var_name.get()] = \ self._connections[self.var_name.get()] = \
(self.var_address.get(), self.var_port.get()) (self.var_address.get(), self.var_port.get())
@@ -138,20 +162,8 @@ class RevPiPlcList(tkinter.Frame):
self.evt_btnnew() self.evt_btnnew()
self.changes = True self.changes = True
def evt_btnclose(self):
if self.changes:
ask = tkmsg.askyesno(
parent=self.master, title="Frage...",
message="Wollen Sie wirklich beenden?\n"
"Nicht gespeicherte Änderungen gehen verloren",
)
else:
ask = True
if ask:
self.master.destroy()
def evt_btnnew(self): def evt_btnnew(self):
u"""Neue Verbindung erstellen."""
self.list_conn.select_clear(0, "end") self.list_conn.select_clear(0, "end")
self.evt_listconn() self.evt_listconn()
@@ -161,13 +173,14 @@ class RevPiPlcList(tkinter.Frame):
self.var_port.set("55123") self.var_port.set("55123")
def evt_btnremove(self): def evt_btnremove(self):
u"""Verbindung löschen."""
item_index = self.list_conn.curselection() item_index = self.list_conn.curselection()
if len(item_index) == 1: if len(item_index) == 1:
item = self.list_conn.get(item_index[0]) item = self.list_conn.get(item_index[0])
ask = tkmsg.askyesno( ask = tkmsg.askyesno(
"Frage", _("Question"),
"Wollen Sie die Ausgewählte Verbindung '{}' wirklich " _("Do you really want to delete the selected connection '{}'?"
"löschen?".format(item), "").format(item),
parent=self.master parent=self.master
) )
if ask: if ask:
@@ -178,21 +191,24 @@ class RevPiPlcList(tkinter.Frame):
self.changes = True self.changes = True
def evt_btnsave(self): def evt_btnsave(self):
u"""Alle Verbindungen speichern."""
if self._saveappdata(): if self._saveappdata():
ask = tkmsg.askyesno( ask = tkmsg.askyesno(
"Information", "Verbindungen erfolgreich gespeichert.\n" _("Information"),
"Möchten Sie dieses Fenster jetzt schließen?", _("Successfully saved. \nDo you want to close this window?"),
parent=self.master parent=self.master
) )
if ask: if ask:
self.master.destroy() self.master.destroy()
else: else:
tkmsg.showerror( tkmsg.showerror(
"Fehler", "Verbindungen konnten nicht gespeichert werden", _("Error"),
_("Failed to save connections"),
parent=self.master parent=self.master
) )
def evt_listconn(self, evt=None): def evt_listconn(self, evt=None):
u"""Übernimmt Einstellungen in Eingabefelder."""
item_index = self.list_conn.curselection() item_index = self.list_conn.curselection()
if len(item_index) == 1: if len(item_index) == 1:
@@ -210,6 +226,7 @@ class RevPiPlcList(tkinter.Frame):
self.btn_remove["state"] = "disabled" self.btn_remove["state"] = "disabled"
def evt_keypress(self, evt=None): def evt_keypress(self, evt=None):
u"""Passt bei Tastendruck den Status der Buttons an."""
okvalue = "normal" if ( okvalue = "normal" if (
self.var_address.get() != "" self.var_address.get() != ""
and self.var_name.get() != "" and self.var_name.get() != ""

View File

@@ -7,24 +7,42 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import gzip import gzip
import os import os
import pickle
import tarfile import tarfile
import tkinter import tkinter
import tkinter.filedialog as tkfd import tkinter.filedialog as tkfd
import tkinter.messagebox as tkmsg import tkinter.messagebox as tkmsg
import zipfile import zipfile
from mytools import gettrans
from os import environ
from os import makedirs
from shutil import rmtree from shutil import rmtree
from tempfile import mktemp, mkdtemp from sys import platform
from tempfile import mkstemp, mkdtemp
from xmlrpc.client import Binary from xmlrpc.client import Binary
# Übersetzung laden
_ = gettrans()
# Systemwerte
if platform == "linux":
homedir = environ["HOME"]
else:
homedir = environ["APPDATA"]
savefile = os.path.join(homedir, ".revpipyplc", "programpath.dat")
class RevPiProgram(tkinter.Frame): class RevPiProgram(tkinter.Frame):
def __init__(self, master, xmlcli, xmlmode, revpi): def __init__(self, master, xmlcli, xmlmode, revpi):
u"""Init RevPiProgram-Class.
@return None"""
if xmlmode < 2: if xmlmode < 2:
return None return None
super().__init__(master) super().__init__(master)
# master.protocol("WM_DELETE_WINDOW", self._checkclose) self.master.protocol("WM_DELETE_WINDOW", self._checkclose)
self.master.bind("<KeyPress-Escape>", self._checkclose)
self.pack(expand=True, fill="both") self.pack(expand=True, fill="both")
self.uploaded = False self.uploaded = False
@@ -33,21 +51,31 @@ class RevPiProgram(tkinter.Frame):
self.xmlmode = xmlmode self.xmlmode = xmlmode
self.xmlstate = "normal" if xmlmode == 3 else "disabled" self.xmlstate = "normal" if xmlmode == 3 else "disabled"
# Letzte Einstellungen übernehmen
self.opt = self._loaddefault()
# Fenster bauen # Fenster bauen
self._createwidgets() self._createwidgets()
self._evt_optdown() self._evt_optdown()
self._evt_optup() self._evt_optup()
# def _checkclose(self): def _checkclose(self, event=None):
# if self.uploaded: u"""Prüft ob Fenster beendet werden soll.
# tkmsg.showinfo("Ein PLC Programm wurde hochgeladen. " @param event tkinter-Event"""
# "Bitte die PLC options prüfen ob dort das neue Programm" if self.uploaded:
# "eingestellt werden muss.") tkmsg.showinfo(
# self.master.destroy() _("Information"),
_("A PLC program has been uploaded. Please check the "
"PLC options to see if the correct program is specified "
"as the start program."),
parent=self.master
)
self.master.destroy()
def _createwidgets(self): def _createwidgets(self):
self.master.wm_title("RevPi Python PLC Programm") u"""Erstellt alle Widgets."""
self.master.wm_title(_("RevPi Python PLC program"))
self.master.wm_resizable(width=False, height=False) self.master.wm_resizable(width=False, height=False)
self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1)
@@ -61,7 +89,7 @@ class RevPiProgram(tkinter.Frame):
# Gruppe Programm # Gruppe Programm
prog = tkinter.LabelFrame(self) prog = tkinter.LabelFrame(self)
prog.columnconfigure(0, weight=1) prog.columnconfigure(0, weight=1)
prog["text"] = "PLC Python programm" prog["text"] = _("PLC python program")
prog.grid(columnspan=2, pady=2, sticky="we") prog.grid(columnspan=2, pady=2, sticky="we")
# Variablen vorbereiten # Variablen vorbereiten
@@ -71,14 +99,26 @@ class RevPiProgram(tkinter.Frame):
self.var_typedown = tkinter.StringVar(prog) self.var_typedown = tkinter.StringVar(prog)
self.var_typeup = tkinter.StringVar(prog) self.var_typeup = tkinter.StringVar(prog)
self.lst_typedown = ["Dateien", "Zip Archiv", "TGZ Archiv"] self.lst_typedown = [_("Files"), _("Zip archive"), _("TGZ archive")]
self.lst_typeup = ["Dateien", "Ordner", "Zip Archiv", "TGZ Archiv"] self.lst_typeup = [
self.var_typedown.set(self.lst_typedown[0]) _("Files"), _("Folder"), _("Zip archive"), _("TGZ archive")
self.var_typeup.set(self.lst_typeup[0]) ]
self.var_picdown.set(self.opt.get("picdown", False))
self.var_picup.set(self.opt.get("picup", False))
# Gespeicherte Werte übernehmen
saved_val = self.opt.get("typedown", self.lst_typedown[0])
self.var_typedown.set(
saved_val if saved_val in self.lst_typedown else _("Files")
)
saved_val = self.opt.get("typeup", self.lst_typeup[0])
self.var_typeup.set(
saved_val if saved_val in self.lst_typeup else _("Files")
)
r = 0 r = 0
lbl = tkinter.Label(prog) lbl = tkinter.Label(prog)
lbl["text"] = "PLC Programm herunterladen als:" lbl["text"] = _("Download PLC program as:")
lbl.grid(column=0, row=r, **cpadw) lbl.grid(column=0, row=r, **cpadw)
opt = tkinter.OptionMenu( opt = tkinter.OptionMenu(
prog, self.var_typedown, *self.lst_typedown, prog, self.var_typedown, *self.lst_typedown,
@@ -88,17 +128,17 @@ class RevPiProgram(tkinter.Frame):
r = 1 r = 1
self.ckb_picdown = tkinter.Checkbutton(prog) self.ckb_picdown = tkinter.Checkbutton(prog)
self.ckb_picdown["text"] = "inkl. piCtory Konfiguration" self.ckb_picdown["text"] = _("include piCtory configuration")
self.ckb_picdown["variable"] = self.var_picdown self.ckb_picdown["variable"] = self.var_picdown
self.ckb_picdown.grid(column=0, row=r, **cpadw) self.ckb_picdown.grid(column=0, row=r, **cpadw)
btn = tkinter.Button(prog) btn = tkinter.Button(prog)
btn["command"] = self.plcdownload btn["command"] = self.plcdownload
btn["text"] = "Download" btn["text"] = _("Download")
btn.grid(column=1, row=r, **cpad) btn.grid(column=1, row=r, **cpad)
r = 2 r = 2
lbl = tkinter.Label(prog) lbl = tkinter.Label(prog)
lbl["text"] = "PLC Programm hochladen als:" lbl["text"] = _("Upload PLC program as:")
lbl.grid(column=0, row=r, **cpadw) lbl.grid(column=0, row=r, **cpadw)
opt = tkinter.OptionMenu( opt = tkinter.OptionMenu(
prog, self.var_typeup, *self.lst_typeup, prog, self.var_typeup, *self.lst_typeup,
@@ -110,64 +150,78 @@ class RevPiProgram(tkinter.Frame):
r = 3 r = 3
ckb = tkinter.Checkbutton(prog) ckb = tkinter.Checkbutton(prog)
ckb["state"] = self.xmlstate ckb["state"] = self.xmlstate
ckb["text"] = "vorher alles im Uploadverzeichnis löschen" ckb["text"] = _("clean upload folder before upload")
ckb["variable"] = self.var_cleanup ckb["variable"] = self.var_cleanup
ckb.grid(column=0, row=r, columnspan=2, **cpadw) ckb.grid(column=0, row=r, columnspan=2, **cpadw)
r = 4 r = 4
self.ckb_picup = tkinter.Checkbutton(prog) self.ckb_picup = tkinter.Checkbutton(prog)
self.ckb_picup["state"] = self.xmlstate self.ckb_picup["state"] = self.xmlstate
self.ckb_picup["text"] = "enthält piCtory Konfiguration" self.ckb_picup["text"] = _("includes piCtory configuration")
self.ckb_picup["variable"] = self.var_picup self.ckb_picup["variable"] = self.var_picup
self.ckb_picup.grid(column=0, row=r, **cpadw) self.ckb_picup.grid(column=0, row=r, **cpadw)
btn = tkinter.Button(prog) btn = tkinter.Button(prog)
btn["command"] = self.plcupload btn["command"] = self.plcupload
btn["state"] = self.xmlstate btn["state"] = self.xmlstate
btn["text"] = "Upload" btn["text"] = _("Upload")
btn.grid(column=1, row=r, **cpad) btn.grid(column=1, row=r, **cpad)
# Gruppe piCtory # Gruppe piCtory
picto = tkinter.LabelFrame(self) picto = tkinter.LabelFrame(self)
picto.columnconfigure(0, weight=1) picto.columnconfigure(0, weight=1)
picto["text"] = "piCtory Konfiguration" picto["text"] = _("piCtory configuration")
picto.grid(columnspan=2, pady=2, sticky="we") picto.grid(columnspan=2, pady=2, sticky="we")
lbl = tkinter.Label(picto) lbl = tkinter.Label(picto)
lbl["text"] = "piCtory Konfiguration herunterladen" lbl["text"] = _("Download piCtory configuration")
lbl.grid(column=0, row=0, **cpadw) lbl.grid(column=0, row=0, **cpadw)
btn = tkinter.Button(picto) btn = tkinter.Button(picto)
btn["command"] = self.getpictoryrsc btn["command"] = self.getpictoryrsc
btn["text"] = "Download" btn["text"] = _("Download")
btn.grid(column=1, row=0, **cpad) btn.grid(column=1, row=0, **cpad)
lbl = tkinter.Label(picto) lbl = tkinter.Label(picto)
lbl["text"] = "piCtory Konfiguration hochladen" lbl["text"] = _("Upload piCtory configuration")
lbl.grid(column=0, row=1, **cpadw) lbl.grid(column=0, row=1, **cpadw)
btn = tkinter.Button(picto) btn = tkinter.Button(picto)
btn["command"] = self.setpictoryrsc btn["command"] = self.setpictoryrsc
btn["state"] = self.xmlstate btn["state"] = self.xmlstate
btn["text"] = "Upload" btn["text"] = _("Upload")
btn.grid(column=1, row=1, **cpad) btn.grid(column=1, row=1, **cpad)
# Gruppe ProcImg # Gruppe ProcImg
proc = tkinter.LabelFrame(self) proc = tkinter.LabelFrame(self)
proc.columnconfigure(0, weight=1) proc.columnconfigure(0, weight=1)
proc["text"] = "piControl0 Prozessabbild" proc["text"] = _("piControl0 process image")
proc.grid(columnspan=2, pady=2, sticky="we") proc.grid(columnspan=2, pady=2, sticky="we")
lbl = tkinter.Label(proc) lbl = tkinter.Label(proc)
lbl["text"] = "Prozessabbild-Dump herunterladen" lbl["text"] = _("Download process image dump")
lbl.grid(column=0, row=0, **cpadw) lbl.grid(column=0, row=0, **cpadw)
btn = tkinter.Button(proc) btn = tkinter.Button(proc)
btn["command"] = self.getprocimg btn["command"] = self.getprocimg
btn["text"] = "Download" btn["text"] = _("Download")
btn.grid(column=1, row=0, **cpad)
# Gruppe piControlReset
picon = tkinter.LabelFrame(self)
picon.columnconfigure(0, weight=1)
picon["text"] = _("Reset piControl")
picon.grid(columnspan=2, pady=2, sticky="we")
lbl = tkinter.Label(picon)
lbl["text"] = _("Execute piControlReset")
lbl.grid(column=0, row=0, **cpadw)
btn = tkinter.Button(picon)
btn["command"] = self.picontrolreset
btn["text"] = _("execute")
btn.grid(column=1, row=0, **cpad) btn.grid(column=1, row=0, **cpad)
# Beendenbutton # Beendenbutton
btn = tkinter.Button(self) btn = tkinter.Button(self)
btn["command"] = self.master.destroy btn["command"] = self._checkclose
btn["text"] = "Beenden" btn["text"] = _("Exit")
btn.grid() btn.grid()
def _evt_optdown(self, text=""): def _evt_optdown(self, text=""):
u"""Passt je nach gewählter Option den Status der Widgets an."""
if self.lst_typedown.index(self.var_typedown.get()) == 0: if self.lst_typedown.index(self.var_typedown.get()) == 0:
self.var_picdown.set(False) self.var_picdown.set(False)
self.ckb_picdown["state"] = "disable" self.ckb_picdown["state"] = "disable"
@@ -175,26 +229,45 @@ class RevPiProgram(tkinter.Frame):
self.ckb_picdown["state"] = "normal" self.ckb_picdown["state"] = "normal"
def _evt_optup(self, text=""): def _evt_optup(self, text=""):
u"""Passt je nach gewählter Option den Status der Widgets an."""
if self.lst_typeup.index(self.var_typeup.get()) <= 1: if self.lst_typeup.index(self.var_typeup.get()) <= 1:
self.var_picup.set(False) self.var_picup.set(False)
self.ckb_picup["state"] = "disable" self.ckb_picup["state"] = "disable"
else: else:
self.ckb_picup["state"] = "normal" self.ckb_picup["state"] = "normal"
def _loaddefault(self): def _loaddefault(self, full=False):
# TODO: letzte Einstellungen laden u"""Übernimmt für den Pi die letzen Pfade.
pass @param full Einstellungen für alle Verbindungen laden
@return dict() mit Einstellungen"""
if os.path.exists(savefile):
fh = open(savefile, "rb")
dict_all = pickle.load(fh)
if full:
return dict_all
else:
return dict_all.get(self.revpi, {})
return {}
def _savedefaults(self): def _savedefaults(self):
# TODO: Einstellungen sichern u"""Schreibt fuer den Pi die letzen Pfade.
pass @return True, bei erfolgreicher Verarbeitung"""
try:
makedirs(os.path.dirname(savefile), exist_ok=True)
dict_all = self._loaddefault(full=True)
dict_all[self.revpi] = self.opt
fh = open(savefile, "wb")
pickle.dump(dict_all, fh)
self.changes = False
except:
return False
return True
def create_filelist(self, rootdir): def create_filelist(self, rootdir):
"""Erstellt eine Dateiliste von einem Verzeichnis. u"""Erstellt eine Dateiliste von einem Verzeichnis.
@param rootdir: Verzeichnis fuer das eine Liste erstellt werden soll @param rootdir Verzeichnis fuer das eine Liste erstellt werden soll
@returns: Dateiliste""" @return Dateiliste"""
filelist = [] filelist = []
print(rootdir)
for tup_dir in os.walk(rootdir): for tup_dir in os.walk(rootdir):
for fname in tup_dir[2]: for fname in tup_dir[2]:
filelist.append(os.path.join(tup_dir[0], fname)) filelist.append(os.path.join(tup_dir[0], fname))
@@ -204,13 +277,12 @@ class RevPiProgram(tkinter.Frame):
"""Gibt das rootdir von einem entpackten Verzeichnis zurueck. """Gibt das rootdir von einem entpackten Verzeichnis zurueck.
Dabei wird geprueft, ob es sich um einen einzelnen Ordner handelt Dabei wird geprueft, ob es sich um einen einzelnen Ordner handelt
und ob es eine piCtory Konfiguraiton im rootdir gibt. und ob es eine piCtory Konfiguration im rootdir gibt.
@param rootdir: Verzeichnis fuer Pruefung @param rootdir Verzeichnis fuer Pruefung
@returns: Abgeaendertes rootdir @return Abgeaendertes rootdir
""" """
lst_dir = os.listdir(rootdir) lst_dir = os.listdir(rootdir)
print(rootdir)
if len(lst_dir) == 1 and \ if len(lst_dir) == 1 and \
os.path.isdir(os.path.join(rootdir, lst_dir[0])): os.path.isdir(os.path.join(rootdir, lst_dir[0])):
return (os.path.join(rootdir, lst_dir[0]), None) return (os.path.join(rootdir, lst_dir[0]), None)
@@ -226,104 +298,180 @@ class RevPiProgram(tkinter.Frame):
return (rootdir, None) return (rootdir, None)
def getpictoryrsc(self): def getpictoryrsc(self):
u"""Läd die piCtory Konfiguration herunter."""
fh = tkfd.asksaveasfile( fh = tkfd.asksaveasfile(
mode="wb", parent=self.master, mode="wb", parent=self.master,
confirmoverwrite=True, confirmoverwrite=True,
title="Speichern als...", title=_("Save as..."),
initialdir=self.opt.get("getpictoryrsc_dir", ""),
initialfile=self.revpi + ".rsc", initialfile=self.revpi + ".rsc",
filetypes=(("piCtory Config", "*.rsc"), ("All Files", "*.*")) filetypes=((_("piCtory config"), "*.rsc"), (_("All files"), "*.*"))
) )
if fh is not None: if fh is not None:
try: try:
fh.write(self.xmlcli.get_pictoryrsc().data) fh.write(self.xmlcli.get_pictoryrsc().data)
except: except:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Datei konnte nicht geladen und gespeichert " _("Could not load and save file!"),
"werden!" parent=self.master,
) )
else: else:
tkmsg.showinfo( tkmsg.showinfo(
parent=self.master, title="Erfolgreich", _("Success"),
message="Datei erfolgreich vom Revolution Pi geladen " _("File successfully loaded and saved."),
"und gespeichert.", parent=self.master
) )
# Einstellungen speichern
self.opt["getpictoryrsc_dir"] = os.path.dirname(fh.name)
self._savedefaults()
finally: finally:
fh.close() fh.close()
def getprocimg(self): def getprocimg(self):
u"""Läd das aktuelle Prozessabbild herunter."""
fh = tkfd.asksaveasfile( fh = tkfd.asksaveasfile(
mode="wb", parent=self.master, mode="wb", parent=self.master,
confirmoverwrite=True, confirmoverwrite=True,
title="Speichern als...", title=_("Save as..."),
initialdir=self.opt.get("getprocimg_dir", ""),
initialfile=self.revpi + ".img", initialfile=self.revpi + ".img",
filetypes=(("Imagefiles", "*.img"), ("All Files", "*.*")) filetypes=((_("Imagefiles"), "*.img"), (_("All files"), "*.*"))
) )
if fh is not None: if fh is not None:
try: try:
fh.write(self.xmlcli.get_procimg().data) fh.write(self.xmlcli.get_procimg().data)
except: except:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Datei konnte nicht geladen und gespeichert" _("Could not load and save file!"),
"werden!" parent=self.master
) )
else: else:
tkmsg.showinfo( tkmsg.showinfo(
parent=self.master, title="Erfolgreich", _("Success"),
message="Datei erfolgreich vom Revolution Pi geladen " _("File successfully loaded and saved."),
"und gespeichert.", parent=self.master
) )
# Einstellungen speichern
self.opt["getprocimg_dir"] = os.path.dirname(fh.name)
self._savedefaults()
finally: finally:
fh.close() fh.close()
def setpictoryrsc(self, filename=None): def setpictoryrsc(self, filename=None):
u"""Überträgt die angegebene piCtory-Konfiguration."""
if filename is None: if filename is None:
fh = tkfd.askopenfile( fh = tkfd.askopenfile(
mode="rb", parent=self.master, mode="rb", parent=self.master,
title="piCtory Datei öffnen...", title=_("Open piCtory file..."),
initialdir=self.opt.get("setpictoryrsc_dir", ""),
initialfile=self.revpi + ".rsc", initialfile=self.revpi + ".rsc",
filetypes=(("piCtory Config", "*.rsc"), ("All Files", "*.*")) filetypes=(
(_("piCtory config"), "*.rsc"), (_("All files"), "*.*")
)
) )
else: else:
fh = open(filename, "rb") fh = open(filename, "rb")
if fh is not None: if fh is not None:
ask = tkmsg.askyesno( ask = tkmsg.askyesno(
parent=self.master, title="Frage", _("Question"),
message="Soll nach dem Hochladen der piCtory Konfiguration " _("Should the piControl driver be reset after "
"ein Reset am piControl Treiber durchgeführt werden?" "uploading the piCtory configuration?"),
parent=self.master
) )
ec = self.xmlcli.set_pictoryrsc(Binary(fh.read()), ask) ec = self.xmlcli.set_pictoryrsc(Binary(fh.read()), ask)
print(ec)
if ec == 0: if ec == 0:
if ask: if ask:
tkmsg.showinfo( tkmsg.showinfo(
parent=self.master, title="Erfolgreich", _("Success"),
message="Die Übertragung der piCtory Konfiguration " _("The transfer of the piCtory configuration "
"und der Reset von piControl wurden erfolgreich " "and the reset of piControl have been "
"ausgeführt") "successfully executed."),
parent=self.master
)
else: else:
tkmsg.showinfo( tkmsg.showinfo(
parent=self.master, title="Erfolgreich", _("Success"),
message="Die Übertragung der piCtory Konfiguration " _("The piCtory configuration was "
"wurde erfolgreich ausgeführt") "successfully transferred."),
parent=self.master
)
# Einstellungen speichern
self.opt["setpictoryrsc_dir"] = os.path.dirname(fh.name)
self._savedefaults()
elif ec == -1:
tkmsg.showerror(
_("Error"),
_("Can not process the transferred file."),
parent=self.master
)
elif ec == -2:
tkmsg.showerror(
_("Error"),
_("Can not find main elements in piCtory file."),
parent=self.master
)
elif ec == -4:
tkmsg.showerror(
_("Error"),
_("Contained devices could not be found on Revolution "
"Pi. The configuration may be from a newer piCtory "
"version!"),
parent=self.master
)
elif ec == -5:
tkmsg.showerror(
_("Error"),
_("Could not load RAP catalog on Revolution Pi."),
parent=self.master
)
elif ec < 0: elif ec < 0:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Die piCtory Konfiguration konnte auf dem " _("The piCtory configuration could not be "
"Revolution Pi nicht geschrieben werden.") "written on the Revolution Pi."),
parent=self.master
)
elif ec > 0: elif ec > 0:
tkmsg.showwarning( tkmsg.showwarning(
parent=self.master, title="Warnung", _("Warning"),
message="Die piCtroy Konfiguration wurde erfolgreich " _("The piCtroy configuration has been saved successfully."
"gespeichert. \nBeim piControl Reset trat allerdings ein " " \nAn error occurred on piControl reset!"),
"Fehler auf!") parent=self.master
)
fh.close() fh.close()
def picontrolreset(self):
u"""Fürt ein Reset der piBridge durch."""
ask = tkmsg.askyesno(
_("Question"),
_("Are you sure to reset piControl? \nThe process image "
"and the piBridge are interrupted !!!"),
parent=self.master
)
if ask:
ec = self.xmlcli.resetpicontrol()
if ec == 0:
tkmsg.showinfo(
_("Success"),
_("piControl reset executed successfully"),
parent=self.master
)
else:
tkmsg.showerror(
_("Error"),
_("piControl reset could not be executed successfully"),
parten=self.master
)
def plcdownload(self): def plcdownload(self):
u"""Läd das aktuelle Projekt herunter."""
tdown = self.lst_typedown.index(self.var_typedown.get()) tdown = self.lst_typedown.index(self.var_typedown.get())
fh = None fh = None
dirselect = "" dirselect = ""
@@ -331,20 +479,26 @@ class RevPiProgram(tkinter.Frame):
if tdown == 0: if tdown == 0:
# Ordner # Ordner
dirselect = tkfd.askdirectory( dirselect = tkfd.askdirectory(
parent=self.master, title="Verzeichnis zum Ablegen", parent=self.master,
mustexist=False, initialdir=self.revpi) title=_("Directory to save"),
mustexist=False,
initialdir=self.opt.get("plcdownload_dir", self.revpi)
)
if type(dirselect) == str and dirselect != "": if type(dirselect) == str and dirselect != "":
fh = open(mktemp(), "wb") fh = open(mkstemp()[1], "wb")
elif tdown == 1: elif tdown == 1:
# Zip # Zip
fh = tkfd.asksaveasfile( fh = tkfd.asksaveasfile(
mode="wb", parent=self.master, mode="wb", parent=self.master,
confirmoverwrite=True, confirmoverwrite=True,
title="Speichern als...", title=_("Save as..."),
initialdir=self.opt.get("plcdownload_file", ""),
initialfile=self.revpi + ".zip", initialfile=self.revpi + ".zip",
filetypes=(("Zip Archiv", "*.zip"), ("All Files", "*.*")) filetypes=(
(_("Zip archive"), "*.zip"), (_("All files"), "*.*")
)
) )
elif tdown == 2: elif tdown == 2:
@@ -352,18 +506,23 @@ class RevPiProgram(tkinter.Frame):
fh = tkfd.asksaveasfile( fh = tkfd.asksaveasfile(
mode="wb", parent=self.master, mode="wb", parent=self.master,
confirmoverwrite=True, confirmoverwrite=True,
title="Speichern als...", title=_("Save as..."),
initialdir=self.opt.get("plcdownload_file", ""),
initialfile=self.revpi + ".tar.gz", initialfile=self.revpi + ".tar.gz",
filetypes=(("Tar Archiv", "*.tar.gz"), ("All Files", "*.*")) filetypes=(
(_("TGZ archive"), "*.tar.gz"), (_("All files"), "*.*")
)
) )
if fh is not None: if fh is not None:
if tdown == 1: if tdown == 1:
plcfile = self.xmlcli.plcdownload( plcfile = self.xmlcli.plcdownload(
"zip", self.var_picdown.get()) "zip", self.var_picdown.get()
)
else: else:
plcfile = self.xmlcli.plcdownload( plcfile = self.xmlcli.plcdownload(
"tar", self.var_picdown.get()) "tar", self.var_picdown.get()
)
try: try:
fh.write(plcfile.data) fh.write(plcfile.data)
@@ -374,44 +533,55 @@ class RevPiProgram(tkinter.Frame):
fh_pack = tarfile.open(fh.name) fh_pack = tarfile.open(fh.name)
# Unterverzeichnis streichen # Unterverzeichnis streichen
rootname = ""
for taritem in fh_pack.getmembers(): for taritem in fh_pack.getmembers():
print(rootname)
if not taritem.name == "revpipyload": if not taritem.name == "revpipyload":
taritem.name = \ taritem.name = \
taritem.name.replace("revpipyload/", "") taritem.name.replace("revpipyload/", "")
fh_pack.extract(taritem, dirselect) fh_pack.extract(taritem, dirselect)
fh_pack.close() fh_pack.close()
self.opt["plcdownload_dir"] = dirselect
else:
self.opt["plcdownload_file"] = os.path.dirname(fh.name)
self.opt["typedown"] = self.var_typedown.get()
self.opt["picdown"] = self.var_picdown.get()
except: except:
raise raise
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Datei konnte nicht geladen und gespeichert " _("Could not load and save file!"),
"werden!" parent=self.master
) )
else: else:
tkmsg.showinfo( tkmsg.showinfo(
parent=self.master, title="Erfolgreich", _("Success"),
message="Datei erfolgreich vom Revolution Pi geladen " _("File successfully loaded and saved."),
"und gespeichert.", parent=self.master
) )
# Einstellungen speichern
self._savedefaults()
finally: finally:
fh.close() fh.close()
def plcupload(self): def plcupload(self):
u"""Lädt das angegebene Projekt auf den RevPi.
@return True, bei erfolgreicher Verarbeitung"""
tup = self.lst_typeup.index(self.var_typeup.get()) tup = self.lst_typeup.index(self.var_typeup.get())
dirselect = "" dirselect = ""
dirtmp = None dirtmp = None
filelist = [] filelist = []
fileselect = None
rscfile = None rscfile = None
if tup == 0: if tup == 0:
# Datei # Datei
fileselect = tkfd.askopenfilenames( fileselect = tkfd.askopenfilenames(
parent=self.master, title="Python Programm übertragen...", parent=self.master,
filetypes=(("Python", "*.py"), ("All Files", "*.*")) title="Upload Python program...",
initialdir=self.opt.get("plcupload_dir", ""),
filetypes=(("Python", "*.py"), (_("All files"), "*.*"))
) )
if type(fileselect) == tuple and len(fileselect) > 0: if type(fileselect) == tuple and len(fileselect) > 0:
for file in fileselect: for file in fileselect:
@@ -420,18 +590,24 @@ class RevPiProgram(tkinter.Frame):
elif tup == 1: elif tup == 1:
# Ordner # Ordner
dirselect = tkfd.askdirectory( dirselect = tkfd.askdirectory(
parent=self.master, title="Verzeichnis zum Hochladen", parent=self.master,
mustexist=True, initialdir=self.revpi) title=_("Folder to upload"),
mustexist=True,
initialdir=self.opt.get("plcupload_dir", self.revpi)
)
if type(dirselect) == str and dirselect != "": if type(dirselect) == str and dirselect != "":
filelist = self.create_filelist(dirselect) filelist = self.create_filelist(dirselect)
elif tup == 2: elif tup == 2:
# Zip # Zip
fileselect = tkfd.askopenfilename( fileselect = tkfd.askopenfilename(
parent=self.master, title="Zip-Archive übertragen...", parent=self.master,
title=_("Upload Zip archive..."),
initialdir=self.opt.get("plcupload_file", ""),
initialfile=self.revpi + ".zip", initialfile=self.revpi + ".zip",
filetypes=(("Zip Archiv", "*.zip"), ("All Files", "*.*")) filetypes=(
(_("Zip archive"), "*.zip"), (_("All files"), "*.*")
)
) )
if type(fileselect) == str and fileselect != "": if type(fileselect) == str and fileselect != "":
# Zipdatei prüfen # Zipdatei prüfen
@@ -446,16 +622,22 @@ class RevPiProgram(tkinter.Frame):
else: else:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Die angegebene Datei ist kein ZIP-Archiv.") _("The specified file is not a ZIP archive."),
parent=self.master
)
return False return False
elif tup == 3: elif tup == 3:
# TarGz # TarGz
fileselect = tkfd.askopenfilename( fileselect = tkfd.askopenfilename(
parent=self.master, title="TarGz-Archiv übertragen...", parent=self.master,
title=_("Upload TarGz archiv..."),
initialdir=self.opt.get("plcupload_file", ""),
initialfile=self.revpi + ".tar.gz", initialfile=self.revpi + ".tar.gz",
filetypes=(("Tar Archiv", "*.tar.gz"), ("All Files", "*.*")) filetypes=(
(_("TGZ archive"), "*.tar.gz"), (_("All files"), "*.*")
)
) )
if type(fileselect) == str and fileselect != "": if type(fileselect) == str and fileselect != "":
@@ -471,8 +653,10 @@ class RevPiProgram(tkinter.Frame):
else: else:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Die angegebene Datei ist kein TAR-Archiv.") _("The specified file is not a TAR archive."),
parent=self.master
)
return False return False
# Wenn keine Dateien gewählt # Wenn keine Dateien gewählt
@@ -482,12 +666,16 @@ class RevPiProgram(tkinter.Frame):
# Vor Übertragung aufräumen wenn ausgewählt # Vor Übertragung aufräumen wenn ausgewählt
if self.var_cleanup.get() and not self.xmlcli.plcuploadclean(): if self.var_cleanup.get() and not self.xmlcli.plcuploadclean():
tkmsg.showerror( tkmsg.showerror(
parent=self.masger, title="Fehler", _("Error"),
message="Beim Löschen der Dateien auf dem Revolution Pi ist " _("There was an error deleting the files on the "
"ein Fehler aufgetreten.") "Revolution Pi."),
parent=self.master
)
return False return False
# Flag setzen, weil ab hier Veränderungen existieren # Aktuell konfiguriertes Programm lesen (für uploaded Flag)
opt_program = self.xmlcli.get_config()
opt_program = opt_program.get("plcprogram", "none.py")
self.uploaded = True self.uploaded = True
ec = 0 ec = 0
@@ -496,7 +684,7 @@ class RevPiProgram(tkinter.Frame):
if fname == rscfile: if fname == rscfile:
continue continue
# TODO: Fehlerabfang bei Dateilesen # FIXME: Fehlerabfang bei Dateilesen
with open(fname, "rb") as fh: with open(fname, "rb") as fh:
# Dateinamen ermitteln # Dateinamen ermitteln
@@ -505,6 +693,10 @@ class RevPiProgram(tkinter.Frame):
else: else:
sendname = fname.replace(dirselect, "")[1:] sendname = fname.replace(dirselect, "")[1:]
# Prüfen ob Dateiname bereits als Startprogramm angegeben ist
if sendname == opt_program:
self.uploaded = False
# Datei übertragen # Datei übertragen
try: try:
ustatus = self.xmlcli.plcupload( ustatus = self.xmlcli.plcupload(
@@ -519,35 +711,51 @@ class RevPiProgram(tkinter.Frame):
if ec == 0: if ec == 0:
tkmsg.showinfo( tkmsg.showinfo(
parent=self.master, title="Erfolgreich", _("Success"),
message="Die Übertragung war erfolgreich.") _("The PLC program was transferred successfully."),
parent=self.master
)
if self.var_picup.get(): if self.var_picup.get():
if rscfile is not None: if rscfile is not None:
self.setpictoryrsc(rscfile) self.setpictoryrsc(rscfile)
else: else:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Es wurde im Archiv keine piCtory " _("There is no piCtory configuration in this "
"Konfiguration gefunden") "archive."),
parent=self.master
)
# Einstellungen speichern
if tup == 0:
self.opt["plcupload_dir"] = os.path.dirname(fileselect[0])
elif tup == 1:
self.opt["plcupload_dir"] = dirselect
else:
self.opt["plcupload_file"] = os.path.dirname(fileselect)
self.opt["typeup"] = self.var_typeup.get()
self.opt["picup"] = self.var_picup.get()
self._savedefaults()
elif ec == -1: elif ec == -1:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Der Revoluton Pi konnte Teile der Übertragung nicht " _("The Revolution Pi could not process some parts of the "
"verarbeiten.") "transmission."),
parent=self.master
)
elif ec == -2: elif ec == -2:
tkmsg.showerror( tkmsg.showerror(
parent=self.master, title="Fehler", _("Error"),
message="Bei der Übertragung traten Fehler auf") _("Errors occurred during transmission"),
parent=self.master
)
# Temp-Dir aufräumen # Temp-Dir aufräumen
if dirtmp is not None: if dirtmp is not None:
rmtree(dirtmp) rmtree(dirtmp)
return True
if __name__ == "__main__":
root = tkinter.Tk()
myapp = RevPiProgram(root, None, "test")
root.mainloop()

View File

@@ -1,55 +1,52 @@
#!/usr/bin/python3 #!/usr/bin/python3
# #
# RevPiPyControl # RevPiPyControl
# Version: 0.2.7 # Version: see global var pycontrolverion
# #
# Webpage: https://revpimodio.org/revpipyplc/ # Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3 # (c) Sven Sager, License: LGPLv3
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import revpicheckclient
import revpiinfo
import revpilogfile import revpilogfile
import revpioption import revpioption
import revpiplclist import revpiplclist
import revpiprogram import revpiprogram
import socket import socket
import sys
import tkinter import tkinter
import tkinter.messagebox as tkmsg import tkinter.messagebox as tkmsg
from functools import partial import webbrowser
from os.path import dirname from mytools import addroot, gettrans
from os.path import join as pathjoin
from xmlrpc.client import ServerProxy from xmlrpc.client import ServerProxy
# Übersetzung laden
_ = gettrans()
def addroot(filename): pycontrolversion = "0.4.1"
u"""Hängt root-dir der Anwendung vor Dateinamen.
Je nach Ausführungsart der Anwendung muss das root-dir über
andere Arten abgerufen werden.
@param filename: Datei oder Ordnername
@returns: root dir
"""
if getattr(sys, "frozen", False):
return pathjoin(dirname(sys.executable), filename)
else:
return pathjoin(dirname(__file__), filename)
class RevPiPyControl(tkinter.Frame): class RevPiPyControl(tkinter.Frame):
def __init__(self, master=None): def __init__(self, master=None):
u"""Init RevPiPyControl-Class.
@param master tkinter master"""
super().__init__(master) super().__init__(master)
self.master.protocol("WM_DELETE_WINDOW", self._closeapp)
self.pack(fill="both", expand=True) self.pack(fill="both", expand=True)
self.cli = None self.cli = None
self.dict_conn = revpiplclist.get_connections() self.dict_conn = revpiplclist.get_connections()
self.errcount = 0 self.errcount = 0
self.revpiname = None self.revpiname = None
self.xmlfuncs = []
self.xmlmode = 0 self.xmlmode = 0
# Debugger vorbereiten
self.debugframe = None
# Globale Fenster # Globale Fenster
self.tkcheckclient = None
self.tklogs = None self.tklogs = None
self.tkoptions = None self.tkoptions = None
self.tkprogram = None self.tkprogram = None
@@ -61,14 +58,38 @@ class RevPiPyControl(tkinter.Frame):
self.tmr_plcrunning() self.tmr_plcrunning()
def _btnstate(self): def _btnstate(self):
u"""Setzt den state der Buttons."""
stateval = "disabled" if self.cli is None else "normal" stateval = "disabled" if self.cli is None else "normal"
self.btn_plclogs["state"] = stateval self.btn_plclogs["state"] = stateval
self.btn_plcstart["state"] = stateval self.btn_plcstart["state"] = stateval
self.btn_plcstop["state"] = stateval self.btn_plcstop["state"] = stateval
self.btn_plcrestart["state"] = stateval self.btn_plcrestart["state"] = stateval
self.btn_debug["state"] = stateval
def _closeall(self):
u"""Schließt alle Fenster."""
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:
self.tkoptions.destroy()
if self.tkprogram is not None:
self.tkprogram.destroy()
if self.debugframe is not None:
self.plcdebug()
self.debugframe.destroy()
self.cli.psstop()
self.debugframe = None
def _closeapp(self, event=None):
u"""Räumt auf und beendet Programm.
@param event tkinter Event"""
self._closeall()
self.master.destroy()
def _createwidgets(self): def _createwidgets(self):
"""Erstellt den Fensterinhalt.""" u"""Erstellt den Fensterinhalt."""
# Hauptfenster # Hauptfenster
self.master.wm_title("RevPi Python PLC Loader") self.master.wm_title("RevPi Python PLC Loader")
self.master.wm_iconphoto( self.master.wm_iconphoto(
@@ -81,36 +102,44 @@ class RevPiPyControl(tkinter.Frame):
self.master.config(menu=self.mbar) self.master.config(menu=self.mbar)
menu1 = tkinter.Menu(self.mbar, tearoff=False) menu1 = tkinter.Menu(self.mbar, tearoff=False)
menu1.add_command(label="Connections...", command=self.plclist) menu1.add_command(label=_("Connections..."), command=self.plclist)
menu1.add_separator() menu1.add_separator()
menu1.add_command(label="Exit", command=self.master.destroy) menu1.add_command(label=_("Exit"), command=self.master.destroy)
self.mbar.add_cascade(label="Main", menu=menu1) self.mbar.add_cascade(label=_("Main"), menu=menu1)
self._fillmbar() self._fillmbar()
self._fillconnbar() self._fillconnbar()
# Hilfe Menü
menu1 = tkinter.Menu(self.mbar, tearoff=False)
menu1.add_command(
label=_("Visit website..."), command=self.visitwebsite)
menu1.add_separator()
menu1.add_command(label=_("Info..."), command=self.infowindow)
self.mbar.add_cascade(label=_("Help"), menu=menu1)
self.var_conn = tkinter.StringVar(self) self.var_conn = tkinter.StringVar(self)
self.txt_connect = tkinter.Entry( self.txt_connect = tkinter.Entry(self, state="readonly", width=40)
self, textvariable=self.var_conn, state="readonly", width=30) self.txt_connect["textvariable"] = self.var_conn
self.txt_connect.pack(fill="x") self.txt_connect.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")
self.btn_plcstart["command"] = self.plcstart self.btn_plcstart["command"] = self.plcstart
self.btn_plcstart.pack(fill="x") self.btn_plcstart.pack(fill="x")
self.btn_plcstop = tkinter.Button(self) self.btn_plcstop = tkinter.Button(self)
self.btn_plcstop["text"] = "PLC Stop" self.btn_plcstop["text"] = _("PLC stop")
self.btn_plcstop["command"] = self.plcstop self.btn_plcstop["command"] = self.plcstop
self.btn_plcstop.pack(fill="x") self.btn_plcstop.pack(fill="x")
self.btn_plcrestart = tkinter.Button(self) self.btn_plcrestart = tkinter.Button(self)
self.btn_plcrestart["text"] = "PLC Restart" self.btn_plcrestart["text"] = _("PLC restart")
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_plclogs = tkinter.Button(self) self.btn_plclogs = tkinter.Button(self)
self.btn_plclogs["text"] = "PLC Logs" self.btn_plclogs["text"] = _("PLC logs")
self.btn_plclogs["command"] = self.plclogs self.btn_plclogs["command"] = self.plclogs
self.btn_plclogs.pack(fill="x") self.btn_plclogs.pack(fill="x")
@@ -120,28 +149,48 @@ class RevPiPyControl(tkinter.Frame):
self.txt_status["textvariable"] = self.var_status self.txt_status["textvariable"] = self.var_status
self.txt_status.pack(fill="x") self.txt_status.pack(fill="x")
self.btn_debug = tkinter.Button(self)
self.btn_debug["text"] = _("PLC watch mode")
self.btn_debug["command"] = self.plcdebug
self.btn_debug.pack(fill="x")
def _fillconnbar(self):
u"""Generiert Menüeinträge für Verbindungen."""
self.mconn.delete(0, "end")
for con in sorted(self.dict_conn.keys(), key=lambda x: x.lower()):
self.mconn.add_command(
label=con, command=lambda con=con: self._opt_conn(con)
)
def _fillmbar(self): def _fillmbar(self):
u"""Generiert Menüeinträge."""
# PLC Menü # PLC Menü
self.mplc = tkinter.Menu(self.mbar, tearoff=False) self.mplc = tkinter.Menu(self.mbar, tearoff=False)
self.mplc.add_command(label="PLC log...", command=self.plclogs) self.mplc.add_command(
#self.mplc.add_command(label="PLC monitor...", command=self.plcmonitor) label=_("PLC log..."), command=self.plclogs)
self.mplc.add_command(label="PLC options...", command=self.plcoptions) self.mplc.add_command(
self.mplc.add_command(label="PLC program...", command=self.plcprogram) label=_("PLC options..."), command=self.plcoptions)
self.mplc.add_command(
label=_("PLC program..."), command=self.plcprogram)
self.mplc.add_separator()
self.mplc.add_command(
label=_("Disconnect"), command=self.serverdisconnect)
self.mbar.add_cascade(label="PLC", menu=self.mplc, state="disabled") self.mbar.add_cascade(label="PLC", menu=self.mplc, state="disabled")
# Connection Menü # Connection Menü
self.mconn = tkinter.Menu(self.mbar, tearoff=False) self.mconn = tkinter.Menu(self.mbar, tearoff=False)
self.mbar.add_cascade(label="Connect", menu=self.mconn) self.mbar.add_cascade(label=_("Connect"), menu=self.mconn)
def _fillconnbar(self): def _opt_conn(self, text, reconnect=False):
self.mconn.delete(0, "end") u"""Stellt eine neue Verbindung zu RevPiPyLoad her.
for con in sorted(self.dict_conn.keys(), key=lambda x: x.lower()): @param text Verbindungsname
self.mconn.add_command( @param reconnect Socket Timeout nicht heruntersetzen"""
label=con, command=partial(self._opt_conn, con) if reconnect:
) socket.setdefaulttimeout(15)
else:
socket.setdefaulttimeout(2)
def _opt_conn(self, text):
socket.setdefaulttimeout(2)
sp = ServerProxy( sp = ServerProxy(
"http://{}:{}".format( "http://{}:{}".format(
self.dict_conn[text][0], int(self.dict_conn[text][1]) self.dict_conn[text][0], int(self.dict_conn[text][1])
@@ -149,6 +198,7 @@ class RevPiPyControl(tkinter.Frame):
) )
# Server prüfen # Server prüfen
try: try:
self.xmlfuncs = sp.system.listMethods()
self.xmlmode = sp.xmlmodus() self.xmlmode = sp.xmlmodus()
except: except:
self.servererror() self.servererror()
@@ -166,86 +216,157 @@ class RevPiPyControl(tkinter.Frame):
)) ))
self.mbar.entryconfig("PLC", state="normal") self.mbar.entryconfig("PLC", state="normal")
def _closeall(self): def infowindow(self):
if self.tklogs is not None: u"""Öffnet das Fenster für die Info."""
self.tklogs.master.destroy()
if self.tkoptions is not None:
self.tkoptions.destroy()
if self.tkprogram is not None:
self.tkprogram.destroy()
def plclist(self):
win = tkinter.Toplevel(self) win = tkinter.Toplevel(self)
revpiplclist.RevPiPlcList(win)
win.focus_set() win.focus_set()
win.grab_set() win.grab_set()
revpiinfo.RevPiInfo(win, self.cli, pycontrolversion)
self.wait_window(win)
self.dict_conn = revpiplclist.get_connections()
self._fillconnbar()
def plcdebug(self):
u"""Baut den Debugframe und packt ihn."""
self.btn_debug["state"] = "disabled"
if "psstart" not in self.xmlfuncs:
tkmsg.showwarning(
_("Warning"),
_("The watch mode ist not supported in version {} "
"of RevPiPyLoad on your RevPi! You need at least version "
"0.4.0. Or the python3-revpimodio module is not installt"
"on your RevPi at least version 0.15.0."
"").format(self.cli.version()),
parent=self.master
)
else:
# Debugfenster laden
if self.debugframe is None \
or self.debugframe.err_workvalues >= \
self.debugframe.max_errors:
self.debugframe = revpicheckclient.RevPiCheckClient(
self, self.cli, self.xmlmode
)
# Show/Hide wechseln
if self.debugframe.winfo_viewable():
self.debugframe.hideallwindows()
if self.debugframe.autorw.get():
self.debugframe.autorw.set(False)
self.debugframe.toggleauto()
self.debugframe.dowrite.set(False)
self.debugframe.pack_forget()
else:
self.debugframe.pack(fill="x")
self.btn_debug["state"] = "normal"
def plclist(self):
u"""Öffnet das Fenster für die Verbindungen."""
win = tkinter.Toplevel(self)
win.focus_set()
win.grab_set()
revpiplclist.RevPiPlcList(win)
self.wait_window(win) self.wait_window(win)
self.dict_conn = revpiplclist.get_connections() self.dict_conn = revpiplclist.get_connections()
self._fillconnbar() self._fillconnbar()
def plclogs(self): def plclogs(self):
u"""Öffnet das Fenster für Logdateien.
@return None"""
if "load_plclog" not in self.xmlfuncs:
tkmsg.showwarning(
_("Warning"),
_("This version of Logviewer ist not supported in version {} "
"of RevPiPyLoad on your RevPi! You need at least version "
"0.4.1.").format(self.cli.version()),
parent=self.master
)
return None
if self.tklogs is None or len(self.tklogs.children) == 0: if self.tklogs is None or len(self.tklogs.children) == 0:
win = tkinter.Toplevel(self) win = tkinter.Toplevel(self)
self.tklogs = revpilogfile.RevPiLogfile(win, self.cli) self.tklogs = revpilogfile.RevPiLogfile(win, self.cli)
else: else:
self.tklogs.focus_set() self.tklogs.focus_set()
def plcmonitor(self):
# TODO: Monitorfenster
pass
def plcoptions(self): def plcoptions(self):
u"""Startet das Optionsfenster."""
if self.xmlmode < 2: if self.xmlmode < 2:
tkmsg.showwarning( tkmsg.showwarning(
parent=self.master, title="Warnung", _("Warning"),
message="Der XML-RPC Modus ist beim RevPiPyLoad nicht hoch " _("XML-RPC access mode in the RevPiPyLoad "
"genug eingestellt, um diesen Dialog zu verwenden!" "configuration is too small to access this dialog!"),
parent=self.master
) )
else: else:
win = tkinter.Toplevel(self) win = tkinter.Toplevel(self)
self.tkoptions = \
revpioption.RevPiOption(win, self.cli, self.xmlmode)
win.focus_set() win.focus_set()
win.grab_set() win.grab_set()
self.tkoptions = \
revpioption.RevPiOption(win, self.cli)
self.wait_window(win) self.wait_window(win)
self.xmlmode = self.tkoptions.xmlmode if self.tkoptions.dc is not None and self.tkoptions.dorestart:
# Wenn XML-Modus anders und Dienstneustart
if self.xmlmode != self.tkoptions.dc["xmlrpc"]:
self.serverdisconnect()
self._opt_conn(self.revpiname, True)
if self.debugframe is not None:
self.cli.psstart()
def plcprogram(self): def plcprogram(self):
u"""Startet das Programmfenster."""
if self.xmlmode < 2: if self.xmlmode < 2:
tkmsg.showwarning( tkmsg.showwarning(
parent=self.master, title="Warnung", _("Warning"),
message="Der XML-RPC Modus ist beim RevPiPyLoad nicht hoch " _("XML-RPC access mode in the RevPiPyLoad "
"genug eingestellt, um diesen Dialog zu verwenden!" "configuration is too small to access this dialog!"),
parent=self.master
) )
else: else:
win = tkinter.Toplevel(self) win = tkinter.Toplevel(self)
self.tkprogram = revpiprogram.RevPiProgram(
win, self.cli, self.xmlmode, self.revpiname)
win.focus_set() win.focus_set()
win.grab_set() win.grab_set()
self.tkprogram = revpiprogram.RevPiProgram(
win, self.cli, self.xmlmode, self.revpiname)
self.wait_window(win) self.wait_window(win)
def plcstart(self): def plcstart(self):
u"""Startet das PLC Programm."""
self.cli.plcstart() self.cli.plcstart()
def plcstop(self): def plcstop(self):
u"""Beendet das PLC Programm."""
self.cli.plcstop() self.cli.plcstop()
def plcrestart(self): def plcrestart(self):
u"""Startet das PLC Programm neu."""
self.cli.plcstop() self.cli.plcstop()
self.cli.plcstart() self.cli.plcstart()
def servererror(self): def serverdisconnect(self):
"""Setzt alles auf NULL.""" u"""Trennt eine bestehende Verbindung."""
self._closeall()
socket.setdefaulttimeout(2) socket.setdefaulttimeout(2)
self.cli = None self.cli = None
self._btnstate() self._btnstate()
self.mbar.entryconfig("PLC", state="disabled") self.mbar.entryconfig("PLC", state="disabled")
self.var_conn.set("") self.var_conn.set("")
self._closeall()
tkmsg.showerror("Fehler", "Server ist nicht erreichbar!") def servererror(self):
u"""Setzt alles zurück für neue Verbindungen."""
self.serverdisconnect()
tkmsg.showerror(
_("Error"),
_("Can not reach server!"),
parent=self.master
)
def tmr_plcrunning(self): def tmr_plcrunning(self):
u"""Timer der den Status des PLC Programms prüft."""
self._btnstate() self._btnstate()
if self.cli is None: if self.cli is None:
self.txt_status["readonlybackground"] = "lightblue" self.txt_status["readonlybackground"] = "lightblue"
@@ -267,16 +388,22 @@ class RevPiPyControl(tkinter.Frame):
plcec = "RUNNING" plcec = "RUNNING"
elif plcec == -2: elif plcec == -2:
plcec = "FILE NOT FOUND" plcec = "FILE NOT FOUND"
elif plcec == -3:
plcec = "NOT RUNNING (NO STATUS)"
elif plcec == -9: elif plcec == -9:
plcec = "PROGRAM KILLED" plcec = "PROGRAM KILLED"
elif plcec == -15: elif plcec == -15:
plcec = "PROGRAMS TERMED" plcec = "PROGRAM TERMED"
elif plcec == 0: elif plcec == 0:
plcec = "NOT RUNNING" plcec = "NOT RUNNING"
self.var_status.set(plcec) self.var_status.set(plcec)
self.master.after(1000, self.tmr_plcrunning) self.master.after(1000, self.tmr_plcrunning)
def visitwebsite(self):
u"""Öffnet auf dem System einen Webbrowser zur Projektseite."""
webbrowser.open("https://revpimodio.org")
if __name__ == "__main__": if __name__ == "__main__":
root = tkinter.Tk() root = tkinter.Tk()

View File

@@ -23,7 +23,7 @@ globsetup = {
"author_email": "akira@narux.de", "author_email": "akira@narux.de",
"url": "https://revpimodio.org/revpipyplc/", "url": "https://revpimodio.org/revpipyplc/",
"license": "LGPLv3", "license": "LGPLv3",
"version": "0.2.7", "version": "0.4.1",
"name": "revpipycontrol", "name": "revpipycontrol",
@@ -49,6 +49,10 @@ if platform == "linux":
("share/applications", ["data/revpipycontrol.desktop"]), ("share/applications", ["data/revpipycontrol.desktop"]),
("share/icons/hicolor/32x32/apps", ["data/revpipycontrol.png"]), ("share/icons/hicolor/32x32/apps", ["data/revpipycontrol.png"]),
("share/revpipycontrol", glob("revpipycontrol/*.*")), ("share/revpipycontrol", glob("revpipycontrol/*.*")),
(
"share/revpipycontrol/locale/de/LC_MESSAGES",
glob("revpipycontrol/locale/de/LC_MESSAGES/*.mo")
),
], ],
install_requires=["tkinter"], install_requires=["tkinter"],
@@ -82,7 +86,7 @@ elif platform == "win32":
options={"build_exe": { options={"build_exe": {
"include_files": [ "include_files": [
"revpipycontrol/revpipycontrol.png", "revpipycontrol/revpipycontrol.png",
# "m4server/locale" "revpipycontrol/locale"
] ]
}}, }},
executables=[exe], executables=[exe],