Merge tag '0.12.0' into pkg/debian

Release version 0.12.0
This commit is contained in:
2026-08-07 08:42:51 +02:00
58 changed files with 1920 additions and 1686 deletions
+3
View File
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11 (revpicommander)" />
</component>
<component name="JavaScriptSettings"> <component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" /> <option name="languageLevel" value="ES6" />
</component> </component>
+28 -23
View File
@@ -8,6 +8,9 @@ APP_NAME = RevPi\ Commander
APP_IDENT = org.revpimodio.revpicommander APP_IDENT = org.revpimodio.revpicommander
APPLE_SIG = "Developer ID Application: Sven Sager (U3N5843D9K)" APPLE_SIG = "Developer ID Application: Sven Sager (U3N5843D9K)"
# Python interpreter to use for venv creation
SYSTEM_PYTHON = python3
# Set path to create the virtual environment with package name # Set path to create the virtual environment with package name
ifdef PYTHON3_VENV ifdef PYTHON3_VENV
VENV_PATH = $(PYTHON3_VENV)/$(PACKAGE) VENV_PATH = $(PYTHON3_VENV)/$(PACKAGE)
@@ -15,39 +18,37 @@ else
VENV_PATH = venv VENV_PATH = venv
endif endif
# If virtualenv exists, use it. If not, use PATH to find commands # Set targets for "all"-target
SYSTEM_PYTHON = python3 all: build-ui build-rc build
PYTHON = $(or $(wildcard $(VENV_PATH)/bin/python), $(SYSTEM_PYTHON))
APP_VERSION = $(shell "$(PYTHON)" src/$(PACKAGE) --version | cut -d ' ' -f 2)
all: build_ui build_rc test build
.PHONY: all .PHONY: all
## Environment ## Virtual environment creation with SYSTEM_PYTHON
venv-info:
@echo Environment for $(APP_NAME) $(APP_VERSION)
@echo Using path: "$(VENV_PATH)"
exit 0
venv: venv:
# Start with empty environment # Start with empty environment
"$(SYSTEM_PYTHON)" -m venv "$(VENV_PATH)" "$(SYSTEM_PYTHON)" -m venv "$(VENV_PATH)"
source "$(VENV_PATH)/bin/activate" && \ "$(VENV_PATH)/bin/pip" install --upgrade pip
python3 -m pip install --upgrade pip && \ "$(VENV_PATH)/bin/pip" install --upgrade -r requirements.txt
python3 -m pip install -r requirements.txt
exit 0
venv-ssp: venv-ssp:
# Include system installed site-packages and add just missing modules # Include system installed site-packages and add just missing modules
"$(SYSTEM_PYTHON)" -m venv --system-site-packages "$(VENV_PATH)" "$(SYSTEM_PYTHON)" -m venv --system-site-packages "$(VENV_PATH)"
source "$(VENV_PATH)/bin/activate" && \ "$(VENV_PATH)/bin/pip" install --upgrade pip
python3 -m pip install --upgrade pip && \ "$(VENV_PATH)/bin/pip" install --upgrade -r requirements.txt
python3 -m pip install -r requirements.txt
exit 0
.PHONY: venv-info venv venv-ssp .PHONY: venv venv-ssp
# Choose python interpreter from venv or system
PYTHON = $(or $(wildcard $(VENV_PATH)/bin/python), $(SYSTEM_PYTHON))
# Read app version from program
APP_VERSION = $(shell "$(PYTHON)" src/$(PACKAGE) --version | cut -d ' ' -f 2)
# Environment info
venv-info:
@echo Environment for $(APP_NAME) $(APP_VERSION)
@echo Using path: "$(VENV_PATH)"
.PHONY: venv-info
## Compile Qt UI files to python code ## Compile Qt UI files to python code
build-ui: build-ui:
@@ -109,6 +110,7 @@ app-licenses:
app: build-ui build-rc app-licenses app: build-ui build-rc app-licenses
"$(PYTHON)" -m PyInstaller -n $(APP_NAME) \ "$(PYTHON)" -m PyInstaller -n $(APP_NAME) \
--collect-submodules=zeroconf \
--add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \ --add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \
--add-data="dist/bundled-libraries.md:$(PACKAGE)/open-source-licenses" \ --add-data="dist/bundled-libraries.md:$(PACKAGE)/open-source-licenses" \
--add-data="dist/open-source-licenses.*:$(PACKAGE)/open-source-licenses" \ --add-data="dist/open-source-licenses.*:$(PACKAGE)/open-source-licenses" \
@@ -123,6 +125,7 @@ app: build-ui build-rc app-licenses
app-mac: build-ui build-rc app-licenses app-mac: build-ui build-rc app-licenses
"$(PYTHON)" -m PyInstaller -n $(APP_NAME) \ "$(PYTHON)" -m PyInstaller -n $(APP_NAME) \
--collect-submodules=zeroconf \
--add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \ --add-data="src/$(PACKAGE)/locale:./$(PACKAGE)/locale" \
--add-data="dist/bundled-libraries.md:$(PACKAGE)/open-source-licenses" \ --add-data="dist/bundled-libraries.md:$(PACKAGE)/open-source-licenses" \
--add-data="dist/open-source-licenses.*:$(PACKAGE)/open-source-licenses" \ --add-data="dist/open-source-licenses.*:$(PACKAGE)/open-source-licenses" \
@@ -164,6 +167,8 @@ clean:
rm -rf build dist src/*.egg-info rm -rf build dist src/*.egg-info
# PyInstaller created files # PyInstaller created files
rm -rf *.spec rm -rf *.spec
# Pycaches
find . -type d -name '__pycache__' -exec rm -r {} \+
distclean: clean distclean: clean
# Virtual environment # Virtual environment
+12 -11
View File
@@ -2,7 +2,7 @@
set PACKAGE=revpicommander set PACKAGE=revpicommander
set APP_NAME=RevPi Commander set APP_NAME=RevPi Commander
set PYTHON=venv\\Scripts\\python.exe set PYTHON=venv\Scripts\python.exe
if "%1" == "venv" goto venv if "%1" == "venv" goto venv
if "%1" == "test" goto test if "%1" == "test" goto test
@@ -24,7 +24,7 @@ goto end
:venv :venv
python -m venv venv python -m venv venv
venv\\Scripts\\pip.exe install -r requirements.txt venv\Scripts\pip.exe install -r requirements.txt
goto end goto end
:test :test
@@ -41,7 +41,7 @@ goto end
mkdir dist mkdir dist
%PYTHON% -m piplicenses ^ %PYTHON% -m piplicenses ^
--format=markdown ^ --format=markdown ^
--output-file dist/bundled-libraries.md --output-file dist\\bundled-libraries.md
%PYTHON% -m piplicenses ^ %PYTHON% -m piplicenses ^
--with-authors ^ --with-authors ^
--with-urls ^ --with-urls ^
@@ -49,7 +49,7 @@ goto end
--with-license-file ^ --with-license-file ^
--no-license-path ^ --no-license-path ^
--format=json ^ --format=json ^
--output-file dist/open-source-licenses.json --output-file dist\\open-source-licenses.json
%PYTHON% -m piplicenses ^ %PYTHON% -m piplicenses ^
--with-authors ^ --with-authors ^
--with-urls ^ --with-urls ^
@@ -57,18 +57,19 @@ goto end
--with-license-file ^ --with-license-file ^
--no-license-path ^ --no-license-path ^
--format=plain-vertical ^ --format=plain-vertical ^
--output-file dist/open-source-licenses.txt --output-file dist\\open-source-licenses.txt
%PYTHON% -m PyInstaller -n "%APP_NAME%" ^ %PYTHON% -m PyInstaller -n "%APP_NAME%" ^
--add-data="dist/bundled-libraries.md;%PACKAGE%\open-source-licenses" ^ --collect-submodules=zeroconf ^
--add-data="dist/open-source-licenses.*;%PACKAGE%\open-source-licenses" ^ --add-data="dist\\bundled-libraries.md;%PACKAGE%\\open-source-licenses" ^
--add-data="src\%PACKAGE%\locale;.\%PACKAGE%\locale" ^ --add-data="dist\\open-source-licenses.*;%PACKAGE%\\open-source-licenses" ^
--add-data="data\%PACKAGE%.ico;." ^ --add-data="src\\%PACKAGE%\\locale;.\\%PACKAGE%\\locale" ^
--add-data="data\\%PACKAGE%.ico;." ^
--icon=data\\%PACKAGE%.ico ^ --icon=data\\%PACKAGE%.ico ^
--noconfirm ^ --noconfirm ^
--clean ^ --clean ^
--onedir ^ --onedir ^
--windowed ^ --windowed ^
src\\%PACKAGE%\\__main__.py src\%PACKAGE%\__main__.py
goto end goto end
:distclean :distclean
@@ -76,7 +77,7 @@ goto end
:clean :clean
rmdir /S /Q .pytest_cache rmdir /S /Q .pytest_cache
rmdir /S /Q build dist src\%PACKAGE%.egg-info rmdir /S /Q build dist src\\%PACKAGE%.egg-info
del /Q *.spec del /Q *.spec
:end :end
+1 -1
View File
@@ -7,6 +7,6 @@ wheel
# Runtime dependencies, must match install_requires in setup.py # Runtime dependencies, must match install_requires in setup.py
keyring>=23.13.1 keyring>=23.13.1
PyQt5>=5.14.1 PyQt5>=5.14.1
paramiko>=2.12.0 asyncssh>=2.14.0
revpimodio2>=2.5.6 revpimodio2>=2.5.6
zeroconf>=0.24.4 zeroconf>=0.24.4
+1 -1
View File
@@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "RevPi Commander" #define MyAppName "RevPi Commander"
#define MyAppVersion "0.11.0" #define MyAppVersion "0.12.0"
#define MyAppPublisher "Sven Sager" #define MyAppPublisher "Sven Sager"
#define MyAppURL "https://revpimodio.org/" #define MyAppURL "https://revpimodio.org/"
#define MyAppICO "data\revpicommander.ico" #define MyAppICO "data\revpicommander.ico"
+1 -1
View File
@@ -19,7 +19,7 @@ setup(
install_requires=[ install_requires=[
"keyring", "keyring",
"PyQt5", "PyQt5",
"paramiko", "asyncssh",
"revpimodio2", "revpimodio2",
"zeroconf" "zeroconf"
], ],
+1 -1
View File
@@ -4,4 +4,4 @@ __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
__package__ = "revpicommander" __package__ = "revpicommander"
__version__ = "0.11.0" __version__ = "0.12.0"
+10 -10
View File
@@ -57,10 +57,10 @@ class AclManager(QtWidgets.QDialog, Ui_diag_aclmanager):
self.__mrk_message_shown += 1 self.__mrk_message_shown += 1
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"There are errors in the ACL list!\nCheck the ALC levels of the " "ACL list contains errors.\nCheck rows highlighted in red. "
"red lines in the table. The ACL levels or ip addresses are " "The ACL levels or IP addresses are invalid. "
"invalid. If you save this dialog again, we will remove the " "If you save this dialog, invalid entries will be "
"wrong entries automatically." "removed automatically."
) )
) )
return True return True
@@ -97,7 +97,7 @@ class AclManager(QtWidgets.QDialog, Ui_diag_aclmanager):
if self._changes_done(): if self._changes_done():
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Do you really want to quit? \nUnsaved changes will be lost" "Quit without saving?\nUnsaved changes will be lost."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
@@ -126,7 +126,7 @@ class AclManager(QtWidgets.QDialog, Ui_diag_aclmanager):
while self.tb_acls.rowCount() > 0: while self.tb_acls.rowCount() > 0:
self.tb_acls.removeRow(0) self.tb_acls.removeRow(0)
self.cbb_level.clear() self.cbb_level.clear()
self.cbb_level.addItem(self.tr("Select..."), -1) self.cbb_level.addItem(self.tr("Select"), -1)
self.lbl_level_info.clear() self.lbl_level_info.clear()
self.__re_ipacl = compile( self.__re_ipacl = compile(
@@ -186,9 +186,9 @@ class AclManager(QtWidgets.QDialog, Ui_diag_aclmanager):
has_error = False has_error = False
tool_tip = "" tool_tip = ""
else: else:
brush = QtGui.QBrush(QtGui.QColor("red")) brush = QtGui.QBrush(QtGui.QColor("#CC6666"))
has_error = True has_error = True
tool_tip = self.tr("This entry has an invalid ACL level or wrong IP format!") tool_tip = self.tr("Invalid ACL level or IP address format.")
for row in range(self.tb_acls.rowCount()): for row in range(self.tb_acls.rowCount()):
item_0 = self.tb_acls.item(row, 0) item_0 = self.tb_acls.item(row, 0)
@@ -370,8 +370,8 @@ class AclManager(QtWidgets.QDialog, Ui_diag_aclmanager):
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not save new ACL entry! Check format of ip address " "Cannot save ACL entry. Check IP address format "
"and acl level is in value list." "and ACL level."
) )
) )
+1 -1
View File
@@ -167,7 +167,7 @@ class AvahiSearch(QtWidgets.QDialog, Ui_diag_search):
return None return None
settings = RevPiSettings() settings = RevPiSettings()
settings.folder = self.tr("Auto discovered") settings.folder = self.tr("Automatically discovered")
settings.name = item.data(WidgetData.host_name) settings.name = item.data(WidgetData.host_name)
settings.address = item.data(WidgetData.address) settings.address = item.data(WidgetData.address)
settings.port = item.data(WidgetData.port) settings.port = item.data(WidgetData.port)
+1 -1
View File
@@ -20,7 +20,7 @@ class BackgroundWorker(QtCore.QThread):
def __init__(self, parent=None, interruption_text: str = None): def __init__(self, parent=None, interruption_text: str = None):
super().__init__(parent) super().__init__(parent)
self._interruption_text = interruption_text or self.tr("User requested cancellation...") self._interruption_text = interruption_text or self.tr("Cancellation requested")
def check_cancel(self) -> bool: def check_cancel(self) -> bool:
""" """
+5 -5
View File
@@ -135,7 +135,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
self.cbx_refresh.setChecked(False) self.cbx_refresh.setChecked(False)
for win in self.dict_windows.values(): # type: DebugIos for win in self.dict_windows.values(): # type: DebugIos
win.stat_bar.showMessage( win.stat_bar.showMessage(
self.tr("Driver reset for piControl detected."), self.tr("piControl driver reset detected"),
10000 10000
) )
self.reload_devices() self.reload_devices()
@@ -175,7 +175,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
for win in self.dict_windows.values(): # type: DebugIos for win in self.dict_windows.values(): # type: DebugIos
win.stat_bar.setStyleSheet("background-color: red;") win.stat_bar.setStyleSheet("background-color: red;")
win.stat_bar.showMessage(self.tr( win.stat_bar.showMessage(self.tr(
"Error while getting values from Revolution Pi." "Error while getting values from RevPi"
), 5000) ), 5000)
return return
@@ -229,9 +229,9 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
win.set_value(io[0], value_procimg) win.set_value(io[0], value_procimg)
if self.cbx_refresh.isChecked(): if self.cbx_refresh.isChecked():
win.stat_bar.showMessage(self.tr("Auto update values..."), 1000) win.stat_bar.showMessage(self.tr("Updating values"), 1000)
else: else:
win.stat_bar.showMessage(self.tr("Values updated..."), 2000) win.stat_bar.showMessage(self.tr("Values updated"), 2000)
if self.driver_reset_detected: if self.driver_reset_detected:
# Show values, which we can recover to empty process image # Show values, which we can recover to empty process image
@@ -269,7 +269,7 @@ class DebugControl(QtWidgets.QWidget, Ui_wid_debugcontrol):
# Create error message # Create error message
device_name = self.dict_devices[lst_result[0]] device_name = self.dict_devices[lst_result[0]]
str_errmsg += self.tr( str_errmsg += self.tr(
"Error set value of device '{0}' Output '{1}': {2}\n" "Error setting value for device '{0}', output '{1}': {2}\n"
).format(device_name, lst_result[1], lst_result[3]) ).format(device_name, lst_result[1], lst_result[3])
else: else:
self.dict_windows[lst_result[0]].reset_change_value_colors(lst_result[1]) self.dict_windows[lst_result[0]].reset_change_value_colors(lst_result[1])
+10 -10
View File
@@ -266,12 +266,12 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
switching_cycles = helper.cm.call_remote_function( switching_cycles = helper.cm.call_remote_function(
"ps_switching_cycles", "ps_switching_cycles",
sender.objectName(), sender.objectName(),
default_value=self.tr("Can not display"), default_value=self.tr("Cannot display"),
) )
if type(switching_cycles) is not list: if type(switching_cycles) is not list:
switching_cycles = [switching_cycles] switching_cycles = [switching_cycles]
for i in range(len(switching_cycles)): for i in range(len(switching_cycles)):
relais_counter = self.tr(" Relais {0}").format(i + 1) relais_counter = self.tr(" Relay {0}").format(i + 1)
if len(switching_cycles) == 1: if len(switching_cycles) == 1:
relais_counter = "" relais_counter = ""
men.addAction( men.addAction(
@@ -284,29 +284,29 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
if sender.property("byte_length") > 4: if sender.property("byte_length") > 4:
# Textbox needs format buttons # Textbox needs format buttons
act_as_text = QtWidgets.QAction(self.tr("as text")) act_as_text = QtWidgets.QAction(self.tr("As text"))
men.addAction(act_as_text) men.addAction(act_as_text)
act_as_number = QtWidgets.QAction(self.tr("as number")) act_as_number = QtWidgets.QAction(self.tr("As number"))
men.addAction(act_as_number) men.addAction(act_as_number)
men.addSeparator() men.addSeparator()
else: else:
act_as_text = None act_as_text = None
act_as_number = None act_as_number = None
act_signed = QtWidgets.QAction(self.tr("signed"), men) act_signed = QtWidgets.QAction(self.tr("Signed"), men)
act_signed.setCheckable(True) act_signed.setCheckable(True)
act_signed.setChecked(sender.property("signed") or False) act_signed.setChecked(sender.property("signed") or False)
if sender.property("bit_address") == -1: if sender.property("bit_address") == -1:
men.addAction(act_signed) men.addAction(act_signed)
act_byteorder = QtWidgets.QAction(self.tr("big_endian"), men) act_byteorder = QtWidgets.QAction(self.tr("Big-endian"), men)
act_byteorder.setCheckable(True) act_byteorder.setCheckable(True)
act_byteorder.setChecked(sender.property("big_endian") or False) act_byteorder.setChecked(sender.property("big_endian") or False)
if sender.property("bit_address") == -1: if sender.property("bit_address") == -1:
men.addAction(act_byteorder) men.addAction(act_byteorder)
if sender.property("byte_length") > 2: if sender.property("byte_length") > 2:
act_wordorder = QtWidgets.QAction(self.tr("switch wordorder")) act_wordorder = QtWidgets.QAction(self.tr("Swap word order"))
act_wordorder.setCheckable(True) act_wordorder.setCheckable(True)
act_wordorder.setChecked(sender.property("word_order") == "big") act_wordorder.setChecked(sender.property("word_order") == "big")
men.addAction(act_wordorder) men.addAction(act_wordorder)
@@ -338,7 +338,7 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
helper.cm.call_remote_function("ps_reset_counter", sender.objectName(), raise_exception=True) helper.cm.call_remote_function("ps_reset_counter", sender.objectName(), raise_exception=True)
except Exception as e: except Exception as e:
log.error(e) log.error(e)
QtWidgets.QMessageBox.critical(self, self.tr("Error"), self.tr("Could not reset the counter value")) QtWidgets.QMessageBox.critical(self, self.tr("Error"), self.tr("Cannot reset counter value."))
if sender.property("frm"): if sender.property("frm"):
sender.setProperty("frm", "{0}{1}".format( sender.setProperty("frm", "{0}{1}".format(
@@ -451,8 +451,8 @@ class DebugIos(QtWidgets.QMainWindow, Ui_win_debugios):
except UnicodeDecodeError: except UnicodeDecodeError:
child.setProperty("struct_type", "number") child.setProperty("struct_type", "number")
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Can not use format text"), self.tr( self, self.tr("Cannot use text format."), self.tr(
"Can not convert bytes {0} to a text for IO '{1}'. Switch to number format instead!" "Cannot convert bytes {0} to text for I/O '{1}'. Switch to number format instead."
).format(value, io_name) ).format(value, io_name)
) )
if child.property("struct_type") == "number": if child.property("struct_type") == "number":
+147 -48
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Helper functions for this application.""" """Helper functions for this application."""
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023-2026 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
import pickle import pickle
@@ -15,10 +15,11 @@ from queue import Queue
from re import search from re import search
from threading import Lock from threading import Lock
from uuid import uuid4 from uuid import uuid4
from xmlrpc.client import Binary, ServerProxy from xmlrpc.client import Binary, ServerProxy, Transport
from configparser import ConfigParser
from PyQt5 import QtCore from PyQt5 import QtCore
from paramiko.ssh_exception import AuthenticationException import asyncssh
from . import proginit as pi from . import proginit as pi
from .ssh_tunneling.server import SSHLocalTunnel from .ssh_tunneling.server import SSHLocalTunnel
@@ -32,6 +33,21 @@ homedir = environ.get("HOME", "") or environ.get("APPDATA", "")
"""Home dir of user.""" """Home dir of user."""
class UnixStreamTransport(Transport):
"""Transport for xmlrpc to use unix domain sockets."""
def __init__(self, socket_path):
super().__init__()
self._socket_path = socket_path
def make_connection(self, host):
import http.client
conn = http.client.HTTPConnection("localhost")
conn.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
conn.sock.connect(self._socket_path)
return conn
class ConnectionFail(IntEnum): class ConnectionFail(IntEnum):
NO_XML_RPC = 1 NO_XML_RPC = 1
SSH_CONNECT = 2 SSH_CONNECT = 2
@@ -91,6 +107,11 @@ class RevPiSettings:
if load_index is not None: if load_index is not None:
self.load_from_index(load_index) self.load_from_index(load_index)
@property
def is_unix_socket(self) -> bool:
"""Check if connection is a unix domain socket."""
return self.address.startswith("/") or self.address.startswith("./")
def load_from_index(self, settings_index: int) -> None: def load_from_index(self, settings_index: int) -> None:
"""Load settings from 'connections' index.""" """Load settings from 'connections' index."""
self._settings.beginReadArray("connections") self._settings.beginReadArray("connections")
@@ -129,8 +150,11 @@ class RevPiSettings:
pass pass
# These values must exists # These values must exists
if not (self.name and self.address and self.port): if not (self.name and self.address):
raise ValueError("Could not geht all required values from saved settings") raise ValueError("Could not get all required values from saved settings")
if not self.is_unix_socket and not self.port:
raise ValueError("Port is required for IP connections")
self._settings.endArray() self._settings.endArray()
@@ -182,7 +206,8 @@ class RevPiSettings:
self._settings.setValue("port", self.port) self._settings.setValue("port", self.port)
self._settings.setValue("timeout", self.timeout) self._settings.setValue("timeout", self.timeout)
self._settings.setValue("ssh_use_tunnel", self.ssh_use_tunnel) # Disable SSH tunnel if unix socket is used. SSH will check the type on the remove system
self._settings.setValue("ssh_use_tunnel", self.ssh_use_tunnel and not self.is_unix_socket)
self._settings.setValue("ssh_port", self.ssh_port) self._settings.setValue("ssh_port", self.ssh_port)
self._settings.setValue("ssh_user", self.ssh_user) self._settings.setValue("ssh_user", self.ssh_user)
self._settings.setValue("ssh_saved_password", self.ssh_saved_password) self._settings.setValue("ssh_saved_password", self.ssh_saved_password)
@@ -342,10 +367,12 @@ class ConnectionManager(QtCore.QThread):
ssh_tunnel_server = None ssh_tunnel_server = None
ssh_tunnel_port = 0 ssh_tunnel_port = 0
ssh_tunnel_socket = None
socket.setdefaulttimeout(revpi_settings.timeout) socket.setdefaulttimeout(revpi_settings.timeout)
if revpi_settings.ssh_use_tunnel: if revpi_settings.ssh_use_tunnel:
# We first connect to find out which target to tunnel
ssh_tunnel_server = SSHLocalTunnel( ssh_tunnel_server = SSHLocalTunnel(
revpi_settings.port, revpi_settings.port,
revpi_settings.address, revpi_settings.address,
@@ -354,10 +381,68 @@ class ConnectionManager(QtCore.QThread):
try: try:
ssh_tunnel_port = ssh_tunnel_server.connect_by_credentials(revpi_settings.ssh_user, ssh_pass) ssh_tunnel_port = ssh_tunnel_server.connect_by_credentials(revpi_settings.ssh_user, ssh_pass)
if getattr(revpi_settings, "ssh_enable_revpipyload", False): # Check for Unix socket on remote system
ssh_tunnel_server.send_cmd("sudo systemctl enable --now revpipyload") try:
stdout, stderr, exit_code = ssh_tunnel_server.send_cmd("cat /etc/revpipyload/revpipyload.conf")
if stdout:
config = ConfigParser()
config.read_string(stdout)
if config.has_section("XMLRPC"):
bindip = config.get("XMLRPC", "bindip", fallback="").strip()
if bindip == "socket":
ssh_tunnel_socket = "/run/revpipyload/xmlrpc.socket"
elif bindip.startswith("/") or bindip.startswith("./"):
ssh_tunnel_socket = bindip
except AuthenticationException: if ssh_tunnel_socket:
log.debug("Using remote unix socket: %s", ssh_tunnel_socket)
# Forward local port 0 (dynamic) to remote unix socket
ssh_tunnel_server.disconnect()
ssh_tunnel_server = SSHLocalTunnel(
ssh_tunnel_socket,
revpi_settings.address,
revpi_settings.ssh_port
)
ssh_tunnel_port = ssh_tunnel_server.connect_by_credentials(
revpi_settings.ssh_user, ssh_pass
)
else:
log.debug("Using remote TCP socket: %s", bindip)
except Exception as e:
log.warning(f"Could not check remote config for unix socket: {e}")
if getattr(revpi_settings, "ssh_enable_revpipyload", False):
cmd_activate_pyload = "systemctl enable --now revpipyload"
# Test sudo requires password authentication
_, _, exit_code = ssh_tunnel_server.send_cmd("sudo -n true")
if exit_code == 0:
# No password required
ssh_tunnel_server.send_cmd(f"sudo {cmd_activate_pyload}")
else:
# Execute command with sudo password
_, _, exit_code = ssh_tunnel_server.send_cmd(
f"sudo -S {cmd_activate_pyload}",
stdin=ssh_pass,
)
if exit_code != 0:
log.error(
"Sudo authentification failed for user %s",
revpi_settings.ssh_user,
)
self.connect_error.emit(
self.tr("Error"), self.tr(
"Can not activate RevPiPyLoad on remote RevPi.\n"
f"Sudo authentification failed for user {revpi_settings.ssh_user}. "
"Please activate RevPiPyLoad manually via Cockpit or CLI."
),
ConnectionFail.NO_XML_RPC_VIA_TUNNEL,
revpi_settings,
)
return False
except asyncssh.PermissionDenied:
self.connect_error.emit( self.connect_error.emit(
self.tr("Error"), self.tr( self.tr("Error"), self.tr(
"The combination of username and password was rejected from the SSH server.\n\n" "The combination of username and password was rejected from the SSH server.\n\n"
@@ -372,17 +457,17 @@ class ConnectionManager(QtCore.QThread):
self._clear_settings() self._clear_settings()
self.connect_error.emit( self.connect_error.emit(
self.tr("Error"), self.tr( self.tr("Error"), self.tr(
"Could not establish a SSH connection to server:\n\n{0}" "Cannot connect to SSH server:\n\n{0}"
).format(str(e)), ).format(str(e)),
ConnectionFail.SSH_CONNECT, ConnectionFail.SSH_CONNECT,
revpi_settings, revpi_settings,
) )
return False return False
sp = ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port)) sp = create_server_proxy(revpi_settings, ssh_tunnel_port)
else: else:
sp = ServerProxy("http://{0}:{1}".format(revpi_settings.address, revpi_settings.port)) sp = create_server_proxy(revpi_settings)
# Load values and test connection to Revolution Pi # Load values and test connection to Revolution Pi
try: try:
@@ -398,11 +483,11 @@ class ConnectionManager(QtCore.QThread):
if revpi_settings.ssh_use_tunnel: if revpi_settings.ssh_use_tunnel:
self.connect_error.emit( self.connect_error.emit(
self.tr("Error"), self.tr( self.tr("Error"), self.tr(
"Can not connect to RevPiPyLoad service through SSH tunnel!\n\n" "Cannot connect to RevPiPyLoad service through SSH tunnel.\n\n"
"This could have the following reasons:\n" "Possible reasons:\n"
"- The RevPiPyLoad service is not running (activate it on your Revolution Pi)\n" "- RevPiPyLoad service is not running. Activate service on your RevPi.\n"
"- The RevPiPyLoad XML-RPC service is NOT bind to localhost\n" "- RevPiPyLoad XML-RPC service is not bound to localhost.\n"
"- The ACL permission is not set for 127.0.0.1!!!" "- ACL permission is not set for 127.0.0.1."
), ),
ConnectionFail.NO_XML_RPC_VIA_TUNNEL, ConnectionFail.NO_XML_RPC_VIA_TUNNEL,
revpi_settings, revpi_settings,
@@ -410,14 +495,14 @@ class ConnectionManager(QtCore.QThread):
else: else:
self.connect_error.emit( self.connect_error.emit(
self.tr("Error"), self.tr( self.tr("Error"), self.tr(
"Can not connect to RevPiPyLoad XML-RPC service! \n\n" "Cannot connect to RevPiPyLoad XML-RPC service.\n\n"
"This could have the following reasons:\n" "Possible reasons:\n"
"- The Revolution Pi is not online\n" "- RevPi is offline.\n"
"- The RevPiPyLoad service is not running (activate it on your Revolution Pi)\n" "- RevPiPyLoad service is not running. Activate service on your RevPi.\n"
"- The RevPiPyLoad XML-RPC service is bind to localhost, only\n" "- RevPiPyLoad XML-RPC service is bound to localhost only.\n"
"- The ACL permission is not set for your IP!!!\n\n" "- The ACL permission is not set for your IP.\n\n"
"Use 'Connect via SSH' to use an encrypted connection or run " "Use 'Connect via SSH' to use encrypted connection or run "
"'sudo revpipyload_secure_installation' on Revolution Pi to setup direct remote access!" "'sudo revpipyload_secure_installation' on RevPi to set up direct remote access."
), ),
ConnectionFail.NO_XML_RPC, ConnectionFail.NO_XML_RPC,
revpi_settings, revpi_settings,
@@ -435,10 +520,7 @@ class ConnectionManager(QtCore.QThread):
with self._lck_cli: with self._lck_cli:
self.ssh_tunnel_server = ssh_tunnel_server self.ssh_tunnel_server = ssh_tunnel_server
self._cli = sp self._cli = sp
self._cli_connect.put_nowait(( self._cli_connect.put_nowait((revpi_settings, ssh_tunnel_port))
"127.0.0.1" if revpi_settings.ssh_use_tunnel else revpi_settings.address,
ssh_tunnel_port if revpi_settings.ssh_use_tunnel else revpi_settings.port
))
self.connection_established.emit() self.connection_established.emit()
@@ -546,14 +628,14 @@ class ConnectionManager(QtCore.QThread):
if self._revpi is not None: if self._revpi is not None:
sp = None sp = None
self.status_changed.emit(self.tr("SIMULATING"), "yellow") self.status_changed.emit(self.tr("Simulating"), "#E3DE48")
elif self._cli is None: elif self._cli is None:
sp = None sp = None
self.status_changed.emit(self.tr("NOT CONNECTED"), "lightblue") self.status_changed.emit(self.tr("Not connected"), "lightblue")
elif not self._cli_connect.empty(): elif not self._cli_connect.empty():
# Get new connection information to create object in this thread # Get new connection information to create object in this thread
item = self._cli_connect.get() revpi_settings, ssh_tunnel_port = self._cli_connect.get()
sp = ServerProxy("http://{0}:{1}".format(*item)) sp = create_server_proxy(revpi_settings, ssh_tunnel_port)
self._cli_connect.task_done() self._cli_connect.task_done()
if sp: if sp:
@@ -566,7 +648,7 @@ class ConnectionManager(QtCore.QThread):
log.warning(e) log.warning(e)
except Exception as e: except Exception as e:
log.warning(e) log.warning(e)
self.status_changed.emit(self.tr("SERVER ERROR"), "red") self.status_changed.emit(self.tr("Server error"), "#CC6666")
self._has_error = True self._has_error = True
self.connection_error_observed.emit("{0} | {1}".format(e, type(e))) self.connection_error_observed.emit("{0} | {1}".format(e, type(e)))
@@ -582,7 +664,7 @@ class ConnectionManager(QtCore.QThread):
self.settings.ssh_user, self.settings.ssh_user,
self.ssh_pass self.ssh_pass
) )
sp = ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port)) sp = create_server_proxy(self.settings, ssh_tunnel_port)
with self._lck_cli: with self._lck_cli:
self.ssh_tunnel_server = ssh_tunnel_server self.ssh_tunnel_server = ssh_tunnel_server
self._cli = sp self._cli = sp
@@ -596,19 +678,19 @@ class ConnectionManager(QtCore.QThread):
self.connection_recovered.emit() self.connection_recovered.emit()
if plc_exit_code == -1: if plc_exit_code == -1:
self.status_changed.emit(self.tr("RUNNING"), "green") self.status_changed.emit(self.tr("Running"), "green")
elif plc_exit_code == -2: elif plc_exit_code == -2:
self.status_changed.emit(self.tr("PLC FILE NOT FOUND"), "red") self.status_changed.emit(self.tr("PLC file not found"), "#CC6666")
elif plc_exit_code == -3: elif plc_exit_code == -3:
self.status_changed.emit(self.tr("NOT RUNNING (NO STATUS)"), "yellow") self.status_changed.emit(self.tr("Not running (no status)"), "#E3DE48")
elif plc_exit_code == -9: elif plc_exit_code == -9:
self.status_changed.emit(self.tr("PROGRAM KILLED"), "red") self.status_changed.emit(self.tr("Program killed"), "#CC6666")
elif plc_exit_code == -15: elif plc_exit_code == -15:
self.status_changed.emit(self.tr("PROGRAM TERMED"), "red") self.status_changed.emit(self.tr("Program terminated"), "#CC6666")
elif plc_exit_code == 0: elif plc_exit_code == 0:
self.status_changed.emit(self.tr("NOT RUNNING"), "yellow") self.status_changed.emit(self.tr("Not running"), "#E3DE48")
else: else:
self.status_changed.emit(self.tr("FINISHED WITH CODE {0}").format(plc_exit_code), "yellow") self.status_changed.emit(self.tr("Finished with exit code {0}").format(plc_exit_code), "#E3DE48")
self.msleep(self._cycle_time) self.msleep(self._cycle_time)
@@ -669,12 +751,8 @@ class ConnectionManager(QtCore.QThread):
Use connection_recovered signal to figure out new parameters. Use connection_recovered signal to figure out new parameters.
""" """
if not self.settings.ssh_use_tunnel and self.settings.address and self.settings.port: ssh_tunnel_port = self.ssh_tunnel_server.local_tunnel_port if self.ssh_tunnel_server else None
return ServerProxy("http://{0}:{1}".format(self.settings.address, self.settings.port)) return create_server_proxy(self.settings, ssh_tunnel_port)
if self.settings.ssh_use_tunnel and self.ssh_tunnel_server and self.ssh_tunnel_server.connected:
return ServerProxy("http://127.0.0.1:{0}".format(self.ssh_tunnel_server.local_tunnel_port))
return None
@property @property
def connected(self) -> bool: def connected(self) -> bool:
@@ -699,6 +777,27 @@ cm = ConnectionManager()
"""Clobal connection manager instance.""" """Clobal connection manager instance."""
def create_server_proxy(revpi_settings: RevPiSettings, ssh_tunnel_port: int = None) -> ServerProxy:
"""
Create a ServerProxy instance based on the given settings.
:param revpi_settings: Revolution Pi saved connection settings
:param ssh_tunnel_port: Use this port if an SSH tunnel is already established
:return: ServerProxy instance
"""
if not ssh_tunnel_port and revpi_settings.is_unix_socket:
return ServerProxy("http://localhost", transport=UnixStreamTransport(revpi_settings.address))
if ssh_tunnel_port:
return ServerProxy("http://127.0.0.1:{0}".format(ssh_tunnel_port))
if revpi_settings.ssh_use_tunnel:
# This case is usually handled by passing ssh_tunnel_port after connecting the tunnel
return ServerProxy("http://127.0.0.1:{0}".format(revpi_settings.port))
return ServerProxy("http://{0}:{1}".format(revpi_settings.address, revpi_settings.port))
def all_revpi_settings() -> [RevPiSettings]: def all_revpi_settings() -> [RevPiSettings]:
"""Get all revpi settings objects.""" """Get all revpi settings objects."""
# Get length of array and close it, the RevPiSettings-class need it # Get length of array and close it, the RevPiSettings-class need it
Binary file not shown.
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -81,7 +81,7 @@ class MqttManager(QtWidgets.QDialog, Ui_diag_mqtt):
if self._changesdone(): if self._changesdone():
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Do you really want to quit? \nUnsaved changes will be lost." "Quit without saving?\nUnsaved changes will be lost."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
if ask: if ask:
@@ -94,7 +94,7 @@ class MqttManager(QtWidgets.QDialog, Ui_diag_mqtt):
if not self._load_settings(): if not self._load_settings():
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not load the MQTT settings dialog. Missing values!" "Cannot load the MQTT settings dialog. Missing values."
) )
) )
return QtWidgets.QDialog.Rejected return QtWidgets.QDialog.Rejected
+2 -2
View File
@@ -100,8 +100,8 @@ def reconfigure_logger():
def filter(self, record: logging.LogRecord) -> bool: def filter(self, record: logging.LogRecord) -> bool:
remove_record = False remove_record = False
# Remove paramiko ssh module # Remove asyncssh module
remove_record = remove_record or record.name.startswith("paramiko") remove_record = remove_record or record.name.startswith("asyncssh")
return not remove_record return not remove_record
+42 -41
View File
@@ -129,7 +129,8 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
# region # REGION: Connection management # region # REGION: Connection management
@QtCore.pyqtSlot(str, str, ConnectionFail, RevPiSettings) @QtCore.pyqtSlot(str, str, ConnectionFail, RevPiSettings)
def on_cm_connect_error(self, title: str, text: str, fail_code: ConnectionFail, revpi_settings: RevPiSettings): def on_cm_connect_error(self, title: str, text: str, fail_code: ConnectionFail,
revpi_settings: RevPiSettings):
""" """
Slot to get information of pyload_connect connection errors. Slot to get information of pyload_connect connection errors.
@@ -138,13 +139,14 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
:param fail_code: Type of error :param fail_code: Type of error
:param revpi_settings: Settings of the revpi with the error :param revpi_settings: Settings of the revpi with the error
""" """
if fail_code is ConnectionFail.NO_XML_RPC_VIA_TUNNEL: if (fail_code is ConnectionFail.NO_XML_RPC_VIA_TUNNEL
and not getattr(revpi_settings, "ssh_enable_revpipyload", False)):
# If RevPiPyLoad is not running, we can try to activate it via ssh # If RevPiPyLoad is not running, we can try to activate it via ssh
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Information"), self.tr( self, self.tr("Information"), self.tr(
"Can not connect to RevPiPyLoad service through SSH tunnel!\n\n" "Cannot connect to the RevPiPyLoad service through the SSH tunnel.\n\n"
"We are trying to activate this service now and reconnect. The settings can be " "Service activation and reconnection in progress. The settings can be "
"changed at any time via 'webstatus'." "changed at any time via Cockpit."
), ),
) )
revpi_settings.ssh_enable_revpipyload = True revpi_settings.ssh_enable_revpipyload = True
@@ -259,9 +261,9 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
diag_connecting = BackgroundWaiter( diag_connecting = BackgroundWaiter(
revpi_settings.timeout, revpi_settings.timeout,
self.tr("Establish a connection to the Revolution Pi..."), self.tr("Connecting to RevPi"),
self, self,
self.tr("Revolution Pi connected!"), self.tr("Connected to RevPi"),
) )
helper.cm.connection_established.connect(diag_connecting.requestInterruption) helper.cm.connection_established.connect(diag_connecting.requestInterruption)
@@ -294,7 +296,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
th_connecting.finished.connect(diag_connecting.requestInterruption) th_connecting.finished.connect(diag_connecting.requestInterruption)
th_connecting.start() th_connecting.start()
diag_connecting.exec_dialog(self.tr("Connecting..."), False) diag_connecting.exec_dialog(self.tr("Connecting"), False)
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_act_connections_triggered(self): def on_act_connections_triggered(self):
@@ -328,18 +330,18 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
if helper.cm.pyload_simulate(configrsc_file, procimg_file, diag.clean_procimg): if helper.cm.pyload_simulate(configrsc_file, procimg_file, diag.clean_procimg):
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Simulator started..."), self.tr( self, self.tr("Simulator started"), self.tr(
"The simulator is running!\n\nYou can work with this simulator if your call " "Simulator is running.\n\nUse the additional "
"RevPiModIO with this additional parameters:\nprocimg={0}\nconfigrsc={1}\n\n" "RevPiModIO parameters:\nprocimg={0}\nconfigrsc={1}\n\n"
"You can copy that from header textbox." "from the header text box."
).format(procimg_file, configrsc_file) ).format(procimg_file, configrsc_file)
) )
else: else:
log.error("Can not start simulator") log.error("Can not start simulator")
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Can not start..."), self.tr( self, self.tr("Cannot start"), self.tr(
"Can not start the simulator! Maybe the piCtory file is corrupt " "Cannot start the simulator. The PiCtory file might be invalid "
"or you have no write permissions for '{0}'." "or you do not have write permissions for '{0}'."
).format(procimg_file) ).format(procimg_file)
) )
@@ -354,8 +356,8 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
if "load_plclog" not in helper.cm.xml_funcs: if "load_plclog" not in helper.cm.xml_funcs:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr( self, self.tr("Warning"), self.tr(
"This version of Logviewer ist not supported in version {0} " "This version of Log Viewer is not supported in version {0} "
"of RevPiPyLoad on your RevPi! You need at least version 0.4.1." "of RevPiPyLoad on your RevPi. At least version 0.4.1 is required."
).format(helper.cm.call_remote_function("version", default_value="-")) ).format(helper.cm.call_remote_function("version", default_value="-"))
) )
return None return None
@@ -375,7 +377,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr( self, self.tr("Warning"), self.tr(
"XML-RPC access mode in the RevPiPyLoad " "XML-RPC access mode in the RevPiPyLoad "
"configuration is too small to access this dialog!" "configuration is too low to access this dialog."
) )
) )
return return
@@ -384,9 +386,9 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
if helper.cm.pyload_version < (0, 6, 0): if helper.cm.pyload_version < (0, 6, 0):
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The Version of RevPiPyLoad on your Revolution Pi ({0}) is to old. " "The version of RevPiPyLoad on your RevPi ({0}) is too old. "
"This Version of RevPiCommander require at least version 0.6.0 " "This version of RevPi Commander requires at least version 0.6.0 "
"of RevPiPyLoad. Please update your Revolution Pi!" "of RevPiPyLoad. Update your RevPi."
) )
) )
return return
@@ -405,7 +407,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr( self, self.tr("Warning"), self.tr(
"XML-RPC access mode in the RevPiPyLoad " "XML-RPC access mode in the RevPiPyLoad "
"configuration is too small to access this dialog!" "configuration is too low to access this dialog."
) )
) )
return return
@@ -414,7 +416,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_act_developer_triggered(self): def on_act_developer_triggered(self):
"""Extent developer mode to main window.""" """Extend developer mode to main window."""
if not helper.cm.connected: if not helper.cm.connected:
return return
@@ -437,10 +439,10 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Are you sure to reset piControl?\n" "Are you sure you want to reset piControl?\n"
"The pictory configuration will be reloaded. During that time " "The PiCtory configuration will be reloaded. During that time, "
"the process image will be interrupted and could rise errors " "the process image will be interrupted and could cause errors "
"on running control programs!" "on running control programs."
) )
) )
if ask != QtWidgets.QMessageBox.Yes: if ask != QtWidgets.QMessageBox.Yes:
@@ -450,14 +452,14 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
if ec == 0: if ec == 0:
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Success"), self.tr( self, self.tr("Success"), self.tr(
"piControl reset executed successfully" "piControl reset completed successfully."
) )
) )
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"piControl reset could not be executed successfully" "piControl reset could not be completed."
) )
) )
@@ -474,7 +476,7 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_act_webpage_triggered(self): def on_act_webpage_triggered(self):
"""Open project page in default browser of operating system.""" """Open project page in default browser of operating system."""
webbrowser.open("https://revpimodio.org") webbrowser.open("https://revpimodio2.readthedocs.io/en/latest/")
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_act_info_triggered(self): def on_act_info_triggered(self):
@@ -504,13 +506,13 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
"""Restart plc program on revolution pi.""" """Restart plc program on revolution pi."""
if helper.cm.simulating: if helper.cm.simulating:
rc = QtWidgets.QMessageBox.question( rc = QtWidgets.QMessageBox.question(
self, self.tr("Reset to piCtory defaults..."), self.tr( self, self.tr("Reset to PiCtory defaults"), self.tr(
"Do you want to reset your process image to {0} values?\n" "Do you want to reset your process image to {0} values?\n"
"You have to stop other RevPiModIO programs before doing that, " "You have to stop other RevPiModIO programs before doing that, "
"because they could reset the outputs." "because they could reset the outputs."
).format( ).format(
self.tr("zero") if helper.settings.value("simulator/restart_zero", False, bool) self.tr("zero") if helper.settings.value("simulator/restart_zero", False, bool)
else self.tr("piCtory default")) else self.tr("PiCtory defaults"))
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
if rc: if rc:
# Set piCtory default values in process image # Set piCtory default values in process image
@@ -531,10 +533,10 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
elif "psstart" not in helper.cm.xml_funcs: elif "psstart" not in helper.cm.xml_funcs:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr( self, self.tr("Warning"), self.tr(
"The watch mode ist not supported in version {0} " "The watch mode is not supported in version {0} "
"of RevPiPyLoad on your RevPi! You need at least version " "of RevPiPyLoad on your RevPi. At least version 0.5.3 "
"0.5.3! Maybe the python3-revpimodio2 module is not " "is required. The python3-revpimodio2 module may be missing "
"installed on your RevPi at least version 2.0.0." "or older than version 2.0.0."
).format(helper.cm.call_remote_function("version", "-")) ).format(helper.cm.call_remote_function("version", "-"))
) )
self.btn_plc_debug.setChecked(False) self.btn_plc_debug.setChecked(False)
@@ -543,8 +545,8 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
elif helper.cm.xml_mode < 1 and not helper.cm.simulating: elif helper.cm.xml_mode < 1 and not helper.cm.simulating:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not load this function, because your ACL level is to low!\n" "Cannot load this function, because your ACL level is too low.\n"
"You need at least level 1 to read or level 3 to write." "At least level 1 to read or level 3 to write is required."
) )
) )
self.btn_plc_debug.setChecked(False) self.btn_plc_debug.setChecked(False)
@@ -558,9 +560,8 @@ class RevPiCommander(QtWidgets.QMainWindow, Ui_win_revpicommander):
debugcontrol.deleteLater() debugcontrol.deleteLater()
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not load piCtory configuration. \n" "Cannot load PiCtory configuration.\n"
"Did you create a hardware configuration? " "Check hardware configuration in PiCtory."
"Please check this in piCtory!"
) )
) )
self.btn_plc_debug.setChecked(False) self.btn_plc_debug.setChecked(False)
+30 -30
View File
@@ -84,7 +84,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
self.dc_settings = {} self.dc_settings = {}
self.tree_files_counter = 0 self.tree_files_counter = 0
self.tree_files_counter_max = 10000 self.tree_files_counter_max = 10000
self.lbl_path_local.setText(helper.cm.settings.watch_path or self.tr("Please select...")) self.lbl_path_local.setText(helper.cm.settings.watch_path or self.tr("Select"))
self.lbl_path_local.setToolTip(self.lbl_path_local.text()) self.lbl_path_local.setToolTip(self.lbl_path_local.text())
self.btn_all.setEnabled(False) self.btn_all.setEnabled(False)
@@ -120,13 +120,13 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if stop_restart and helper.cm.call_remote_function("plcstop") is None: if stop_restart and helper.cm.call_remote_function("plcstop") is None:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not stop plc program on Revolution Pi." "Cannot stop PLC program on RevPi."
) )
) )
return return
uploader = UploadFiles(self.file_list_local(), self) uploader = UploadFiles(self.file_list_local(), self)
if uploader.exec_dialog(self.tr("File transfer...")) == QtWidgets.QDialog.Rejected: if uploader.exec_dialog(self.tr("File transfer")) == QtWidgets.QDialog.Rejected:
return return
if uploader.ec == 0: if uploader.ec == 0:
@@ -134,7 +134,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if not uploader.plc_program_included: if not uploader.plc_program_included:
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Information"), self.tr( self, self.tr("Information"), self.tr(
"A PLC program has been uploaded. Please check the " "A PLC program has been uploaded. Check the "
"PLC program settings to see if the correct program " "PLC program settings to see if the correct program "
"is specified as the start program." "is specified as the start program."
) )
@@ -143,7 +143,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
elif uploader.ec == -1: elif uploader.ec == -1:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The Revolution Pi could not process some parts of the " "RevPi cannot process some parts of the "
"transmission." "transmission."
) )
) )
@@ -151,13 +151,13 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
elif uploader.ec == -2: elif uploader.ec == -2:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self, self.tr("Error"),
self.tr("Errors occurred during transmission") self.tr("Errors occurred during transmission.")
) )
if stop_restart and helper.cm.call_remote_function("plcstart", default_value=1) != 0: if stop_restart and helper.cm.call_remote_function("plcstart", default_value=1) != 0:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr( self, self.tr("Warning"), self.tr(
"Could not start the plc program on Revolution Pi." "Cannot start the PLC program on RevPi."
) )
) )
@@ -169,7 +169,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if "set_plcprogram" in helper.cm.xml_funcs: if "set_plcprogram" in helper.cm.xml_funcs:
self.btn_mark_plcprogram.setEnabled(False) self.btn_mark_plcprogram.setEnabled(False)
self.btn_mark_plcprogram.setToolTip(self.tr( self.btn_mark_plcprogram.setToolTip(self.tr(
"Set as start file" "Set as start program."
)) ))
if len(self.tree_files_revpi.selectedItems()) == 1: if len(self.tree_files_revpi.selectedItems()) == 1:
item = self.tree_files_revpi.selectedItems()[0] item = self.tree_files_revpi.selectedItems()[0]
@@ -177,7 +177,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
else: else:
self.btn_mark_plcprogram.setEnabled(False) self.btn_mark_plcprogram.setEnabled(False)
self.btn_mark_plcprogram.setToolTip(self.tr( self.btn_mark_plcprogram.setToolTip(self.tr(
"Upgrade your Revolution Pi! This function needs at least 'revpipyload' 0.11.0" "Upgrade your RevPi. This function needs at least 'revpipyload' 0.11.0."
)) ))
self.btn_all.setEnabled(state_local) self.btn_all.setEnabled(state_local)
@@ -186,17 +186,17 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if "plcdeletefile" not in helper.cm.xml_funcs: if "plcdeletefile" not in helper.cm.xml_funcs:
self.btn_delete_revpi.setEnabled(False) self.btn_delete_revpi.setEnabled(False)
self.btn_delete_revpi.setToolTip(self.tr( self.btn_delete_revpi.setToolTip(self.tr(
"Upgrade your Revolution Pi! This function needs at least 'revpipyload' 0.9.5" "Upgrade your RevPi. This function needs at least 'revpipyload' 0.9.5."
)) ))
else: else:
self.btn_delete_revpi.setEnabled(state_revpi) self.btn_delete_revpi.setEnabled(state_revpi)
self.btn_delete_revpi.setToolTip(self.tr( self.btn_delete_revpi.setToolTip(self.tr(
"Deletes selected files immediately on the Revolution Pi" "Deletes selected files immediately on RevPi."
)) ))
if "plcdownload_file" not in helper.cm.xml_funcs: if "plcdownload_file" not in helper.cm.xml_funcs:
self.btn_to_left.setEnabled(False) self.btn_to_left.setEnabled(False)
self.btn_to_left.setToolTip(self.tr( self.btn_to_left.setToolTip(self.tr(
"Upgrade your Revolution Pi! This function needs at least 'revpipyload' 0.9.5" "Upgrade your RevPi. This function needs at least 'revpipyload' 0.9.5."
)) ))
elif not helper.cm.settings.watch_path: elif not helper.cm.settings.watch_path:
self.btn_to_left.setEnabled(False) self.btn_to_left.setEnabled(False)
@@ -275,7 +275,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if not os.path.exists(base_dir): if not os.path.exists(base_dir):
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not open last directory '{0}'." "Cannot open last directory '{0}'."
).format(base_dir) ).format(base_dir)
) )
return return
@@ -332,7 +332,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if not silent and self.tree_files_counter > self.tree_files_counter_max: if not silent and self.tree_files_counter > self.tree_files_counter_max:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Stop scanning for files, because we found more than {0} files." "Stopped scanning for files because more than {0} files were found."
).format(self.tree_files_counter_max) ).format(self.tree_files_counter_max)
) )
@@ -373,7 +373,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
lst_revpi = helper.cm.call_remote_function("get_filelist") lst_revpi = helper.cm.call_remote_function("get_filelist")
self.dc_settings = helper.cm.call_remote_function("get_config", default_value={}) self.dc_settings = helper.cm.call_remote_function("get_config", default_value={})
self.lbl_path_revpi.setText( self.lbl_path_revpi.setText(
self.dc_settings.get("plcworkdir", self.tr("Could not load path of working dir")) self.dc_settings.get("plcworkdir", self.tr("Cannot load the working directory path."))
) )
self.lbl_path_revpi.setToolTip(self.lbl_path_revpi.text()) self.lbl_path_revpi.setToolTip(self.lbl_path_revpi.text())
@@ -439,7 +439,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
elif not silent: elif not silent:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not load file list from Revolution Pi." "Cannot load file list from RevPi."
) )
) )
@@ -470,7 +470,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
log.debug("RevPiFiles.on_btn_select_clicked") log.debug("RevPiFiles.on_btn_select_clicked")
diag_folder = QtWidgets.QFileDialog( diag_folder = QtWidgets.QFileDialog(
self, self.tr("Select folder..."), self, self.tr("Select folder"),
helper.cm.settings.watch_path, helper.cm.settings.watch_path,
) )
diag_folder.setFileMode(QtWidgets.QFileDialog.DirectoryOnly) diag_folder.setFileMode(QtWidgets.QFileDialog.DirectoryOnly)
@@ -482,7 +482,7 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if not os.access(selected_dir, os.R_OK): if not os.access(selected_dir, os.R_OK):
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not access the folder '{0}' to read files." "Cannot access the folder '{0}' to read files."
) )
) )
helper.cm.settings.watch_files = [] helper.cm.settings.watch_files = []
@@ -531,17 +531,17 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
rc = rc.data rc = rc.data
if not rc: if not rc:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error..."), self.tr( self, self.tr("Error"), self.tr(
"Error while download file '{0}'." "Error while downloading file '{0}'."
).format(file_name) ).format(file_name)
) )
else: else:
file_name = os.path.join(helper.cm.settings.watch_path, file_name) file_name = os.path.join(helper.cm.settings.watch_path, file_name)
if override is None and os.path.exists(file_name): if override is None and os.path.exists(file_name):
rc_diag = QtWidgets.QMessageBox.question( rc_diag = QtWidgets.QMessageBox.question(
self, self.tr("Override files..."), self.tr( self, self.tr("Overwrite files"), self.tr(
"One or more files does exist on your computer! Do you want to override the existing" "One or more files already exist on your computer. Do you want to overwrite the existing "
"files?\n\nSelect 'Yes' to override, 'No' to download only missing files." "files?\n\nSelect 'Yes' to overwrite, 'No' to download only missing files."
), ),
buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel buttons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel
) )
@@ -571,8 +571,8 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
lst_delete.append(item.data(0, WidgetData.file_name)) lst_delete.append(item.data(0, WidgetData.file_name))
rc = QtWidgets.QMessageBox.question( rc = QtWidgets.QMessageBox.question(
self, self.tr("Delete files from Revolution Pi..."), self.tr( self, self.tr("Delete files from RevPi"), self.tr(
"Do you want to delete {0} files from revolution pi?" "Do you want to delete {0} files from RevPi?"
).format(len(lst_delete)) ).format(len(lst_delete))
) )
if rc != QtWidgets.QMessageBox.Yes: if rc != QtWidgets.QMessageBox.Yes:
@@ -582,8 +582,8 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
rc = helper.cm.call_remote_function("plcdeletefile", file_name, default_value=False) rc = helper.cm.call_remote_function("plcdeletefile", file_name, default_value=False)
if not rc: if not rc:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error..."), self.tr( self, self.tr("Error"), self.tr(
"Error while delete file '{0}'." "Error while deleting file '{0}'."
).format(file_name) ).format(file_name)
) )
@@ -601,9 +601,9 @@ class RevPiFiles(QtWidgets.QMainWindow, Ui_win_files):
if saved is None: if saved is None:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The settings could not be saved on the Revolution Pi!\n" "Cannot save settings on RevPi.\n"
"Try to save the values one mor time and check the log " "Try saving the values one more time and check the "
"files of RevPiPyLoad if the error rises again." "RevPiPyLoad log files if the error occurs again."
) )
) )
+1 -1
View File
@@ -44,7 +44,7 @@ class RevPiInfo(QtWidgets.QDialog, Ui_diag_revpiinfo):
elif helper.cm.connected: elif helper.cm.connected:
lst = helper.cm.call_remote_function( lst = helper.cm.call_remote_function(
"get_filelist", "get_filelist",
default_value=[self.tr("Can not load file list")] default_value=[self.tr("Cannot load file list.")]
) )
else: else:
lst = [self.tr("Not connected")] lst = [self.tr("Not connected")]
+1 -1
View File
@@ -207,7 +207,7 @@ class RevPiLogfile(QtWidgets.QMainWindow, Ui_win_revpilogfile):
if not success: if not success:
textwidget.clear() textwidget.clear()
textwidget.setPlainText(self.tr("Can not access log file on the RevPi")) textwidget.setPlainText(self.tr("Cannot access log file on RevPi."))
elif text != "": elif text != "":
# Function will add \n automatically # Function will add \n automatically
textwidget.appendPlainText(text.strip("\n")) textwidget.appendPlainText(text.strip("\n"))
+16 -16
View File
@@ -187,7 +187,7 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"The settings will be set on the Revolution Pi now.\n\n" "Applying settings on RevPi.\n\n"
"ACL changes and service settings are applied immediately." "ACL changes and service settings are applied immediately."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
@@ -234,9 +234,9 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The settings could not be saved on the Revolution Pi!\n" "Cannot save settings on RevPi\n"
"Try to save the values one mor time and check the log " "Try saving the values one more time and check the "
"files of RevPiPyLoad if the error rises again." "RevPiPyLoad log files if the error occurs again."
) )
) )
@@ -244,7 +244,7 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
if self._changesdone(): if self._changesdone():
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Do you really want to quit? \nUnsaved changes will be lost." "Quit without saving?\nUnsaved changes will be lost."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
@@ -273,7 +273,7 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
default_value=False default_value=False
) )
self.lbl_server_status.setText( self.lbl_server_status.setText(
self.tr("running") if running else self.tr("stopped") self.tr("Running") if running else self.tr("Stopped")
) )
self.lbl_server_status.setStyleSheet( self.lbl_server_status.setStyleSheet(
"color: green" if running else "color: red" "color: green" if running else "color: red"
@@ -292,7 +292,7 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
self.cbx_mqtt.setToolTip("") self.cbx_mqtt.setToolTip("")
self.btn_mqtt.setVisible(True) self.btn_mqtt.setVisible(True)
self.lbl_mqtt_status.setText( self.lbl_mqtt_status.setText(
self.tr("running") if running else self.tr("stopped") self.tr("Running") if running else self.tr("Stopped")
) )
self.lbl_mqtt_status.setStyleSheet( self.lbl_mqtt_status.setStyleSheet(
"color: green" if running else "color: red" "color: green" if running else "color: red"
@@ -323,8 +323,8 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
def on_btn_aclplcserver_clicked(self): def on_btn_aclplcserver_clicked(self):
"""Start ACL manager to edit ACL entries.""" """Start ACL manager to edit ACL entries."""
self.diag_aclmanager.setup_acl_manager(self.acl_plcserver, { self.diag_aclmanager.setup_acl_manager(self.acl_plcserver, {
0: self.tr("read only"), 0: self.tr("Read-only"),
1: self.tr("read and write"), 1: self.tr("Read/write"),
}) })
self.diag_aclmanager.read_only = helper.cm.xml_mode < 4 self.diag_aclmanager.read_only = helper.cm.xml_mode < 4
if self.diag_aclmanager.exec() == QtWidgets.QDialog.Accepted: if self.diag_aclmanager.exec() == QtWidgets.QDialog.Accepted:
@@ -345,8 +345,8 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
self.mrk_xml_ask = QtWidgets.QMessageBox.question( self.mrk_xml_ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Are you sure you want to deactivate the XML-RPC server? " "Are you sure you want to deactivate the XML-RPC server? "
"You will NOT be able to access the Revolution Pi with " "RevPi will no longer be accessible from "
"this program after saving the options!" "this program after saving settings."
) )
) == QtWidgets.QMessageBox.No ) == QtWidgets.QMessageBox.No
if self.mrk_xml_ask: if self.mrk_xml_ask:
@@ -355,11 +355,11 @@ class RevPiOption(QtWidgets.QDialog, Ui_diag_options):
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_btn_aclxmlrpc_clicked(self): def on_btn_aclxmlrpc_clicked(self):
self.diag_aclmanager.setup_acl_manager(self.acl_xmlrpc, { self.diag_aclmanager.setup_acl_manager(self.acl_xmlrpc, {
0: self.tr("Start/Stop PLC program and read logs"), 0: self.tr("Start/stop PLC program and read log files"),
1: self.tr("+ read IOs in watch mode"), 1: self.tr("+ Read I/Os in watch mode"),
2: self.tr("+ read properties and download PLC program"), 2: self.tr("+ Read properties and download PLC program"),
3: self.tr("+ upload PLC program"), 3: self.tr("+ Upload PLC program"),
4: self.tr("+ set properties") 4: self.tr("+ Set properties")
}) })
self.diag_aclmanager.read_only = helper.cm.xml_mode < 4 self.diag_aclmanager.read_only = helper.cm.xml_mode < 4
if self.diag_aclmanager.exec() == QtWidgets.QDialog.Accepted: if self.diag_aclmanager.exec() == QtWidgets.QDialog.Accepted:
+42 -10
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Saved connections of Revolution Pi devices.""" """Saved connections of Revolution Pi devices."""
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023-2026 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
from enum import IntEnum from enum import IntEnum
@@ -16,6 +16,7 @@ from . import proginit as pi
from .helper import RevPiSettings, WidgetData from .helper import RevPiSettings, WidgetData
from .ui.revpiplclist_ui import Ui_diag_connections from .ui.revpiplclist_ui import Ui_diag_connections
DEFAULT_SOCKET_ADDRESS = "/run/revpipyload/xmlrpc.socket"
log = getLogger(__name__) log = getLogger(__name__)
@@ -40,6 +41,8 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
self.lbl_port.setText(self.lbl_port.text().format(self.__default_port)) self.lbl_port.setText(self.lbl_port.text().format(self.__default_port))
self.sbx_port.setValue(self.__default_port) self.sbx_port.setValue(self.__default_port)
self._mrk_address = ""
# Dirty workaround to remove default button to prevent action on ENTER key, while user edit texts # Dirty workaround to remove default button to prevent action on ENTER key, while user edit texts
self.__btn_dummy = QtWidgets.QPushButton(self) self.__btn_dummy = QtWidgets.QPushButton(self)
self.__btn_dummy.setVisible(False) self.__btn_dummy.setVisible(False)
@@ -134,7 +137,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
if self.changes: if self.changes:
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Do you really want to quit? \nUnsaved changes will be lost." "Quit without saving?\nUnsaved changes will be lost."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
@@ -189,12 +192,21 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
up_ok = index > 0 up_ok = index > 0
down_ok = index < self.tre_connections.topLevelItemCount() - 1 down_ok = index < self.tre_connections.topLevelItemCount() - 1
address = self.txt_address.text()
is_unix_socket = address.startswith("/") or address.startswith("./")
is_unix_default = address.lower() == DEFAULT_SOCKET_ADDRESS
# Value isn't saved in settings, resulting of address value
with QtCore.QSignalBlocker(self.cbx_local_socket):
self.cbx_local_socket.setChecked(is_unix_default)
self.btn_up.setEnabled(up_ok) self.btn_up.setEnabled(up_ok)
self.btn_down.setEnabled(down_ok) self.btn_down.setEnabled(down_ok)
self.btn_delete.setEnabled(con_item or dir_item) self.btn_delete.setEnabled(con_item or dir_item)
self.txt_name.setEnabled(con_item) self.txt_name.setEnabled(con_item)
self.txt_address.setEnabled(con_item) self.txt_address.setEnabled(con_item and not is_unix_default)
self.sbx_port.setEnabled(con_item) self.cbx_local_socket.setEnabled(con_item)
self.sbx_port.setEnabled(con_item and not is_unix_socket)
self.sbx_timeout.setEnabled(con_item) self.sbx_timeout.setEnabled(con_item)
self.cbb_folder.setEnabled(con_item or dir_item) self.cbb_folder.setEnabled(con_item or dir_item)
self.cbb_folder.setEditable(dir_item) self.cbb_folder.setEditable(dir_item)
@@ -202,9 +214,9 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
# Disable auto complete, this would override a new typed name with existing one # Disable auto complete, this would override a new typed name with existing one
self.cbb_folder.setCompleter(None) self.cbb_folder.setCompleter(None)
self.cbx_ssh_use_tunnel.setEnabled(con_item) self.cbx_ssh_use_tunnel.setEnabled(con_item and not is_unix_socket)
self.sbx_ssh_port.setEnabled(con_item) self.sbx_ssh_port.setEnabled(con_item and not is_unix_socket)
self.txt_ssh_user.setEnabled(con_item) self.txt_ssh_user.setEnabled(con_item and not is_unix_socket)
def _get_folder_item(self, name: str): def _get_folder_item(self, name: str):
"""Find the folder entry by name.""" """Find the folder entry by name."""
@@ -243,7 +255,6 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
def on_tre_connections_currentItemChanged( def on_tre_connections_currentItemChanged(
self, current: QtWidgets.QTreeWidgetItem, previous: QtWidgets.QTreeWidgetItem): self, current: QtWidgets.QTreeWidgetItem, previous: QtWidgets.QTreeWidgetItem):
self._edit_state()
self._load_cbb_folder() self._load_cbb_folder()
if current and current.type() == NodeType.CON: if current and current.type() == NodeType.CON:
@@ -271,6 +282,9 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
self.__current_item = QtWidgets.QTreeWidgetItem() self.__current_item = QtWidgets.QTreeWidgetItem()
self.cbb_folder.setCurrentText(current.text(0) if current else "") self.cbb_folder.setCurrentText(current.text(0) if current else "")
self._mrk_address = ""
self._edit_state()
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_btn_up_clicked(self): def on_btn_up_clicked(self):
self._move_item(-1) self._move_item(-1)
@@ -303,8 +317,8 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
if item_to_remove.childCount(): if item_to_remove.childCount():
rc = QtWidgets.QMessageBox.question( rc = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"If you remote this folder, all containing elements will be removed, too. \n\n" "If you remove this folder, all contained items will be removed as well.\n\n"
"Do you want to delete folder and all elements?" "Do you want to delete the folder and all contained items?"
), ),
) )
if rc != QtWidgets.QMessageBox.Yes: if rc != QtWidgets.QMessageBox.Yes:
@@ -319,6 +333,8 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
elif item_to_remove and item_to_remove.type() == NodeType.CON: elif item_to_remove and item_to_remove.type() == NodeType.CON:
remove_item(item_to_remove) remove_item(item_to_remove)
self._edit_state()
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_btn_add_clicked(self, settings_preset: RevPiSettings = None): def on_btn_add_clicked(self, settings_preset: RevPiSettings = None):
"""Create new element.""" """Create new element."""
@@ -369,6 +385,7 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
settings = self.__current_item.data(0, WidgetData.revpi_settings) # type: RevPiSettings settings = self.__current_item.data(0, WidgetData.revpi_settings) # type: RevPiSettings
settings.address = text settings.address = text
self.changes = True self.changes = True
self._edit_state()
@QtCore.pyqtSlot(int) @QtCore.pyqtSlot(int)
def on_sbx_port_valueChanged(self, value: int): def on_sbx_port_valueChanged(self, value: int):
@@ -386,6 +403,21 @@ class RevPiPlcList(QtWidgets.QDialog, Ui_diag_connections):
settings.timeout = value settings.timeout = value
self.changes = True self.changes = True
@QtCore.pyqtSlot(int)
def on_cbx_local_socket_stateChanged(self, check_state: int):
if self.__current_item.type() != NodeType.CON:
return
if check_state == QtCore.Qt.CheckState.Checked:
# Backup fields to restore the text if unchecked
self._mrk_address = self.txt_address.text()
self.txt_address.setText(DEFAULT_SOCKET_ADDRESS)
self.on_txt_address_textEdited(self.txt_address.text())
else:
# Restore old address if it is not the default to unlock the address field
self.txt_address.setText("" if self._mrk_address == DEFAULT_SOCKET_ADDRESS else self._mrk_address)
self.on_txt_address_textEdited(self.txt_address.text())
@QtCore.pyqtSlot(int) @QtCore.pyqtSlot(int)
def on_cbx_ssh_use_tunnel_stateChanged(self, check_state: int): def on_cbx_ssh_use_tunnel_stateChanged(self, check_state: int):
if self.__current_item.type() != NodeType.CON: if self.__current_item.type() != NodeType.CON:
+52 -52
View File
@@ -105,7 +105,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if self.cbb_plcprogram.currentText() == "": if self.cbb_plcprogram.currentText() == "":
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"You have to select a start program, before uploading the " "You must select a start program before uploading the "
"settings." "settings."
) )
) )
@@ -113,9 +113,9 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"The settings will be set on the Revolution Pi now.\n\n" "Saving settings on RevPi.\n\n"
"If you made changes on the 'PCL Program' section, your plc " "If you made changes in the 'PLC Program' section, your PLC "
"program will restart now!" "program will be restarted."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
@@ -137,9 +137,9 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The settings could not be saved on the Revolution Pi!\n" "Cannot save settings on RevPi.\n"
"Try to save the values one mor time and check the log " "Try saving the values one more time and check the "
"files of RevPiPyLoad if the error rises again." "RevPiPyLoad log files if the error occurs again."
) )
) )
@@ -147,7 +147,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if self._changesdone(): if self._changesdone():
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Question"), self.tr( self, self.tr("Question"), self.tr(
"Do you really want to quit? \nUnsaved changes will be lost." "Quit without saving?\nUnsaved changes will be lost."
) )
) == QtWidgets.QMessageBox.Yes ) == QtWidgets.QMessageBox.Yes
@@ -186,10 +186,10 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
fh.close() fh.close()
ask = QtWidgets.QMessageBox.question( ask = QtWidgets.QMessageBox.question(
self, self.tr("Reset driver..."), self.tr( self, self.tr("Reset driver"), self.tr(
"Reset piControl driver after successful uploading new piCtory " "Reset piControl driver after successfully uploading the new PiCtory "
"configuration?\nThe process image will be interrupted for a " "configuration?\nThe process image will be interrupted for a "
"short time!" "short time."
), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel ), QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel
) )
if ask == QtWidgets.QMessageBox.Cancel: if ask == QtWidgets.QMessageBox.Cancel:
@@ -202,8 +202,8 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if ec is None: if ec is None:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Got an network error while send data to Revolution Pi.\n" "Network error while sending data to RevPi.\n"
"Please try again." "Try again."
) )
) )
elif ec == 0: elif ec == 0:
@@ -211,7 +211,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if ask == QtWidgets.QMessageBox.Yes: if ask == QtWidgets.QMessageBox.Yes:
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Success"), self.tr( self, self.tr("Success"), self.tr(
"The transfer of the piCtory configuration " "The transfer of the PiCtory configuration "
"and the reset of piControl have been " "and the reset of piControl have been "
"successfully executed." "successfully executed."
), ),
@@ -219,47 +219,47 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
else: else:
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Success"), self.tr( self, self.tr("Success"), self.tr(
"The piCtory configuration was successfully transferred." "The PiCtory configuration was successfully transferred."
) )
) )
elif ec == -1: elif ec == -1:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not process the transferred file." "Cannot process the transferred file."
) )
) )
elif ec == -2: elif ec == -2:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Can not find main elements in piCtory file." "Cannot find main elements in PiCtory file."
) )
) )
elif ec == -4: elif ec == -4:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Contained devices could not be found on Revolution " "Cannot find contained devices on RevPi.\n"
"Pi. The configuration may be from a newer piCtory version!" "The configuration may be from a newer PiCtory version."
) )
) )
elif ec == -5: elif ec == -5:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Could not load RAP catalog on Revolution Pi." "Cannot load RAP catalog on RevPi."
) )
) )
elif ec < 0: elif ec < 0:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The piCtory configuration could not be " "Cannot write PiCtory configuration "
"written on the Revolution Pi." "on RevPi."
) )
) )
elif ec > 0: elif ec > 0:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Warning"), self.tr( self, self.tr("Warning"), self.tr(
"The piCtroy configuration has been saved successfully.\n" "The PiCtory configuration has been saved successfully.\n"
"An error occurred on piControl reset!" "An error occurred on piControl reset."
) )
) )
@@ -321,7 +321,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if self.cbb_format.currentIndex() == 0: if self.cbb_format.currentIndex() == 0:
# Save files as zip archive # Save files as zip archive
diag_save = QtWidgets.QFileDialog( diag_save = QtWidgets.QFileDialog(
self, self.tr("Save ZIP archive..."), self, self.tr("Save ZIP archive"),
helper.cm.settings.last_zip_file or "{0}.zip".format(helper.cm.settings.name), helper.cm.settings.last_zip_file or "{0}.zip".format(helper.cm.settings.name),
self.tr("ZIP archive (*.zip);;All files (*.*)") self.tr("ZIP archive (*.zip);;All files (*.*)")
) )
@@ -339,7 +339,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
elif self.cbb_format.currentIndex() == 1: elif self.cbb_format.currentIndex() == 1:
# Save files as TarGz archive # Save files as TarGz archive
diag_save = QtWidgets.QFileDialog( diag_save = QtWidgets.QFileDialog(
self, self.tr("Save TGZ archive..."), self, self.tr("Save TGZ archive"),
helper.cm.settings.last_tar_file or "{0}.tgz".format(helper.cm.settings.name), helper.cm.settings.last_tar_file or "{0}.tgz".format(helper.cm.settings.name),
self.tr("TGZ archive (*.tgz);;All files (*.*)") self.tr("TGZ archive (*.tgz);;All files (*.*)")
) )
@@ -367,7 +367,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if plcfile is None: if plcfile is None:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Could not load PLC program from Revolution Pi." "Cannot load PLC program from RevPi."
) )
) )
@@ -380,8 +380,8 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
log.error(e) log.error(e)
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Coud not save the archive or extract the files!\n" "Cannot save the archive or extract the files.\n"
"Please retry.") "Try again.")
) )
else: else:
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
@@ -411,7 +411,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if self.cbb_format.currentIndex() == 0: if self.cbb_format.currentIndex() == 0:
# Upload zip archive content # Upload zip archive content
diag_open = QtWidgets.QFileDialog( diag_open = QtWidgets.QFileDialog(
self, self.tr("Upload content of ZIP archive..."), self, self.tr("Upload content of ZIP archive"),
helper.cm.settings.last_file_upload, helper.cm.settings.last_file_upload,
self.tr("ZIP archive (*.zip);;All files (*.*)") self.tr("ZIP archive (*.zip);;All files (*.*)")
) )
@@ -437,7 +437,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The selected file ist not a ZIP archive." "The selected file is not a ZIP archive."
) )
) )
return return
@@ -445,7 +445,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
elif self.cbb_format.currentIndex() == 1: elif self.cbb_format.currentIndex() == 1:
# Upload TarGz content # Upload TarGz content
diag_open = QtWidgets.QFileDialog( diag_open = QtWidgets.QFileDialog(
self, self.tr("Upload content of TAR archive..."), self, self.tr("Upload content of TAR archive"),
helper.cm.settings.last_file_upload, helper.cm.settings.last_file_upload,
self.tr("TAR archive (*.tgz);;All files (*.*)") self.tr("TAR archive (*.tgz);;All files (*.*)")
) )
@@ -471,7 +471,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The selected file ist not a TAR archive." "The selected file is not a TAR archive."
) )
) )
return return
@@ -479,8 +479,8 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
# No files selected # No files selected
if len(lst_files) == 0: if len(lst_files) == 0:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("No files to upload..."), self.tr( self, self.tr("No files to upload"), self.tr(
"Found no files to upload in given location or archive." "No files found in the selected location or archive."
) )
) )
remove_temp() remove_temp()
@@ -491,8 +491,8 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if self.cbx_clear.isChecked() and not clean_revpi: if self.cbx_clear.isChecked() and not clean_revpi:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"There was an error deleting the files on the Revolution Pi.\n" "Cannot delete files on RevPi.\n"
"Upload aborted! Please try again." "Upload aborted. Try again."
) )
) )
remove_temp() remove_temp()
@@ -545,10 +545,10 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if plc_program_not_in_upload: if plc_program_not_in_upload:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Information"), self.tr( self, self.tr("Information"), self.tr(
"Could not find the selected PLC start program in " "Cannot find the selected PLC start program in "
"uploaded files.\nThis is not an error, if the file " "the uploaded files.\nThis is not an error if the file "
"was already on the Revolution Pi. Check PLC start " "already exists on RevPi. Check the PLC start program "
"program field" "field."
) )
) )
@@ -558,14 +558,14 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
else: else:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"There is no piCtory configuration in this archive." "There is no PiCtory configuration in this archive."
) )
) )
elif ec == -1: elif ec == -1:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"The Revolution Pi could not process some parts of the transmission." "RevPi cannot process some parts of the transmission."
) )
) )
@@ -590,12 +590,12 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
return return
diag_save = QtWidgets.QFileDialog( diag_save = QtWidgets.QFileDialog(
self, self.tr("Save piCtory file..."), self, self.tr("Save PiCtory file"),
os.path.join( os.path.join(
helper.cm.settings.last_dir_pictory, helper.cm.settings.last_dir_pictory,
"{0}.rsc".format(helper.cm.settings.name) "{0}.rsc".format(helper.cm.settings.name)
), ),
self.tr("piCtory file (*.rsc);;All files (*.*)") self.tr("PiCtory file (*.rsc);;All files (*.*)")
) )
diag_save.setAcceptMode(QtWidgets.QFileDialog.AcceptSave) diag_save.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
diag_save.setDefaultSuffix("rsc") diag_save.setDefaultSuffix("rsc")
@@ -610,7 +610,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if bin_buffer is None: if bin_buffer is None:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Could not load piCtory file from Revolution Pi." "Cannot load PiCtory file from RevPi."
) )
) )
else: else:
@@ -620,7 +620,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Success"), self.tr( self, self.tr("Success"), self.tr(
"piCtory configuration successfully loaded and saved to:\n{0}." "PiCtory configuration saved to:\n{0}."
).format(filename) ).format(filename)
) )
@@ -630,9 +630,9 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
return return
diag_open = QtWidgets.QFileDialog( diag_open = QtWidgets.QFileDialog(
self, self.tr("Upload piCtory file..."), self, self.tr("Upload PiCtory file"),
helper.cm.settings.last_pictory_file or "{0}.rsc".format(helper.cm.settings.name), helper.cm.settings.last_pictory_file or "{0}.rsc".format(helper.cm.settings.name),
self.tr("piCtory file (*.rsc);;All files (*.*)") self.tr("PiCtory file (*.rsc);;All files (*.*)")
) )
diag_open.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) diag_open.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen)
diag_open.setFileMode(QtWidgets.QFileDialog.ExistingFile) diag_open.setFileMode(QtWidgets.QFileDialog.ExistingFile)
@@ -652,7 +652,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
diag_save = QtWidgets.QFileDialog( diag_save = QtWidgets.QFileDialog(
self, self,
self.tr("Save piControl file..."), self.tr("Save piControl file"),
os.path.join( os.path.join(
helper.cm.settings.last_dir_picontrol, helper.cm.settings.last_dir_picontrol,
"{0}.img".format(helper.cm.settings.name) "{0}.img".format(helper.cm.settings.name)
@@ -673,7 +673,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
if bin_buffer is None: if bin_buffer is None:
QtWidgets.QMessageBox.critical( QtWidgets.QMessageBox.critical(
self, self.tr("Error"), self.tr( self, self.tr("Error"), self.tr(
"Could not load process image from Revolution Pi." "Cannot load process image from RevPi."
) )
) )
else: else:
@@ -683,7 +683,7 @@ class RevPiProgram(QtWidgets.QDialog, Ui_diag_program):
QtWidgets.QMessageBox.information( QtWidgets.QMessageBox.information(
self, self.tr("Success"), self.tr( self, self.tr("Success"), self.tr(
"Process image successfully loaded and saved to:\n{0}." "Process image saved to:\n{0}."
).format(filename) ).format(filename)
) )
+2 -2
View File
@@ -77,9 +77,9 @@ class Simulator(QtWidgets.QDialog, Ui_diag_simulator):
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def on_btn_configrsc_clicked(self) -> None: def on_btn_configrsc_clicked(self) -> None:
diag_open = QtWidgets.QFileDialog( diag_open = QtWidgets.QFileDialog(
self, self.tr("Select downloaded piCtory file..."), self, self.tr("Select downloaded PiCtory file"),
helper.settings.value("simulator/last_dir", ".", str), helper.settings.value("simulator/last_dir", ".", str),
self.tr("piCtory file (*.rsc);;All files (*.*)") self.tr("PiCtory file (*.rsc);;All files (*.*)")
) )
diag_open.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) diag_open.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen)
diag_open.setFileMode(QtWidgets.QFileDialog.ExistingFile) diag_open.setFileMode(QtWidgets.QFileDialog.ExistingFile)
+142 -118
View File
@@ -1,112 +1,100 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Connect to a remote host and tunnel a port. Connect to a remote host and tunnel a port.
This was crated on base of the paramiko library demo file forward.py, see on
GitHub https://github.com/paramiko/paramiko/blob/main/demos/forward.py
""" """
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023-2026 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
import select import asyncio
import threading
from logging import getLogger from logging import getLogger
from socketserver import BaseRequestHandler, ThreadingTCPServer
from threading import Thread
from typing import Tuple, Union from typing import Tuple, Union
from paramiko.client import MissingHostKeyPolicy, SSHClient import asyncssh
from paramiko.rsakey import RSAKey
from paramiko.ssh_exception import PasswordRequiredException
from paramiko.transport import Transport
log = getLogger("ssh_tunneling") log = getLogger("ssh_tunneling")
class ForwardServer(ThreadingTCPServer):
daemon_threads = True
allow_reuse_address = True
class Handler(BaseRequestHandler):
def handle(self):
try:
chan = self.ssh_transport.open_channel(
"direct-tcpip",
(self.chain_host, self.chain_port),
self.request.getpeername(),
)
except Exception as e:
log.error(e)
return
if chan is None:
log.error("Could not create a ssh channel")
return
while True:
r, w, x = select.select([self.request, chan], [], [], 5.0)
if self.request in r:
data = self.request.recv(1024)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
self.request.send(data)
chan.close()
self.request.close()
class SSHLocalTunnel: class SSHLocalTunnel:
def __init__(self, remote_tunnel_port: int, ssh_host: str, ssh_port: int = 22): def __init__(self, remote_target: Union[int, str], ssh_host: str, ssh_port: int = 22):
""" """
Connect to a ssh remote host and tunnel a port to your host. Connect to a ssh remote host and tunnel a port or unix socket to your host.
:param remote_tunnel_port: Port on the remote host to tunnel through ssh :param remote_target: Port or unix socket path on the remote host to tunnel through ssh
:param ssh_host: ssh remote host address :param ssh_host: ssh remote host address
:param ssh_port: ssh remote host port :param ssh_port: ssh remote host port
""" """
self._remote_tunnel_port = remote_tunnel_port self._remote_target = remote_target
self._ssh_host = ssh_host self._ssh_host = ssh_host
self._ssh_port = ssh_port self._ssh_port = ssh_port
self._th_server = Thread() self._loop: asyncio.AbstractEventLoop | None = None
self._stop_event: asyncio.Event | None = None
self._thread: threading.Thread | None = None
self._ssh_client = SSHClient() self._started = threading.Event()
self._ssh_client.set_missing_host_key_policy(MissingHostKeyPolicy()) self._stopped = threading.Event()
self._ssh_transport = None # type: Transport self._startup_error: Exception | None = None
self._forward_server = None # type: ThreadingTCPServer self._runtime_error: Exception | None = None
self._local_tunnel_port = None # type: int
def __th_target(self): self._conn: asyncssh.SSHClientConnection | None = None
"""Server thread for socket mirror.""" self._server: asyncssh.SSHForwarder | None = None
self._forward_server.serve_forever() self._local_tunnel_port: int | None = None
def _configure_forward_server(self) -> int: def _thread_main(self, username, password=None, client_keys=None, passphrase=None):
""" try:
Configure forward server for port mirror. asyncio.run(self._run(username, password, client_keys, passphrase))
except Exception as exc:
if not self._started.is_set():
self._startup_error = exc
self._started.set()
else:
self._runtime_error = exc
finally:
self._stopped.set()
:return: Local port on wich the remote port is connected async def _run(self, username, password=None, client_keys=None, passphrase=None):
""" self._loop = asyncio.get_running_loop()
self._ssh_transport = self._ssh_client.get_transport() self._stop_event = asyncio.Event()
class SubHandler(Handler): try:
chain_host = "127.0.0.1" async with asyncssh.connect(
chain_port = self._remote_tunnel_port host=self._ssh_host,
ssh_transport = self._ssh_transport port=self._ssh_port,
username=username,
password=password,
client_keys=client_keys,
passphrase=passphrase,
known_hosts=None, # Analog zu MissingHostKeyPolicy()
config=None, # Do not parse local config
) as conn:
self._conn = conn
# Forward local port 0 (dynamic) to remote target (port or unix socket)
if isinstance(self._remote_target, int):
self._server = await conn.forward_local_port(
'127.0.0.1', 0, '127.0.0.1', self._remote_target
)
else:
self._server = await conn.forward_local_port_to_path(
'127.0.0.1', 0, self._remote_target
)
self._local_tunnel_port = self._server.get_port()
self._forward_server = ForwardServer(("127.0.0.1", 0), SubHandler) self._started.set()
self._local_tunnel_port = self._forward_server.socket.getsockname()[1] await self._stop_event.wait()
self._th_server = Thread(target=self.__th_target) self._server.close()
self._th_server.start() await self._server.wait_closed()
return self._local_tunnel_port except Exception as exc:
if not self._started.is_set():
self._startup_error = exc
self._started.set()
return
raise
def connect_by_credentials(self, username: str, password: str) -> int: def connect_by_credentials(self, username: str, password: str) -> int:
""" """
@@ -114,17 +102,31 @@ class SSHLocalTunnel:
:return: Local port on wich the remote port is connected :return: Local port on wich the remote port is connected
""" """
if self._th_server.is_alive(): if self._thread and self._thread.is_alive():
raise RuntimeError("Already connected") raise RuntimeError("Already connected")
self._ssh_client.connect( self._started.clear()
hostname=self._ssh_host, self._stopped.clear()
port=self._ssh_port, self._startup_error = None
username=username, self._runtime_error = None
password=password,
)
return self._configure_forward_server() self._thread = threading.Thread(
target=self._thread_main,
args=(username, password),
daemon=True
)
self._thread.start()
if not self._started.wait(20.0):
self.disconnect()
raise TimeoutError("SSH connection timed out")
if self._startup_error:
error = self._startup_error
self.disconnect()
raise error
return self._local_tunnel_port
def connect_by_keyfile(self, username: str, key_file: str, key_password: str = None) -> int: def connect_by_keyfile(self, username: str, key_file: str, key_password: str = None) -> int:
""" """
@@ -132,70 +134,92 @@ class SSHLocalTunnel:
:return: Local port on wich the remote port is connected :return: Local port on wich the remote port is connected
""" """
if self._th_server.is_alive(): if self._thread and self._thread.is_alive():
raise RuntimeError("Already connected") raise RuntimeError("Already connected")
if self.key_file_password_protected(key_file): self._started.clear()
private_key = RSAKey.from_private_key_file(key_file, key_password) self._stopped.clear()
else: self._startup_error = None
private_key = RSAKey.from_private_key_file(key_file) self._runtime_error = None
self._ssh_client.connect( self._thread = threading.Thread(
hostname=self._ssh_host, target=self._thread_main,
port=self._ssh_port, args=(username, None, [key_file], key_password),
username=username, daemon=True
pkey=private_key,
look_for_keys=True,
) )
self._thread.start()
return self._configure_forward_server() if not self._started.wait(20.0):
self.disconnect()
raise TimeoutError("SSH connection timed out")
if self._startup_error:
error = self._startup_error
self.disconnect()
raise error
return self._local_tunnel_port
def disconnect(self): def disconnect(self):
"""Close SSH tunnel connection.""" """Close SSH tunnel connection."""
if self._loop and self._stop_event:
self._loop.call_soon_threadsafe(self._stop_event.set)
if self._thread and self._thread.is_alive():
self._thread.join(timeout=5.0)
self._conn = None
self._server = None
self._local_tunnel_port = None self._local_tunnel_port = None
if self._forward_server: self._thread = None
self._forward_server.shutdown() self._loop = None
self._forward_server.server_close() self._stop_event = None
if self._ssh_transport:
self._ssh_transport.close()
self._ssh_client.close()
@staticmethod @staticmethod
def key_file_password_protected(key_file: str) -> bool: def key_file_password_protected(key_file: str) -> bool:
# asyncssh doesn't have a direct equivalent without trying to load it.
# But we can try to load it with an empty passphrase.
try: try:
RSAKey.from_private_key_file(key_file) asyncssh.read_private_key(key_file, passphrase=None)
except PasswordRequiredException:
return True
return False return False
except asyncssh.KeyImportError:
return True
except Exception:
return True
def send_cmd(self, cmd: str, timeout: float = None) -> Union[Tuple[str, str], Tuple[None, None]]: def send_cmd(self, cmd: str, timeout: float = None, stdin: str = None) -> Union[Tuple[str, str, int], Tuple[None, None, None]]:
""" """
Send simple command to ssh host. Send simple command to ssh host.
The output of stdout and stderr is returned as a tuple of two elements.
This elements could be None, in case of an internal error.
:param cmd: Shell command to execute on remote host :param cmd: Shell command to execute on remote host
:param timeout: Timeout for execution :param timeout: Timeout for execution
:return: Tuple with stdout and stderr :param stdin: Send this string to stdin
:return: Tuple with stdout, stderr, exit status
""" """
if not self._th_server.is_alive(): if not self.connected:
raise RuntimeError("Not connected") raise RuntimeError("Not connected")
try: # Running async command from sync context
_, stdout, stderr = self._ssh_client.exec_command(cmd, 1024, timeout) async def _exec():
buffer_out = stdout.read() result = await self._conn.run(cmd, timeout=timeout, input=stdin)
buffer_err = stderr.read() return result.stdout, result.stderr, result.exit_status
return buffer_out.decode(), buffer_err.decode() try:
future = asyncio.run_coroutine_threadsafe(_exec(), self._loop)
stdout, stderr, exit_status = future.result(timeout=timeout)
if type(stdout) is bytes:
stdout = stdout.decode(errors="ignore")
if type(stderr) is bytes:
stderr = stderr.decode(errors="ignore")
return stdout, stderr, exit_status
except Exception as e: except Exception as e:
log.error(e) log.error(e)
return None, None return None, None, None
@property @property
def connected(self): def connected(self):
"""Check connection state of ssh tunnel.""" """Check connection state of ssh tunnel."""
return self._ssh_transport and self._ssh_transport.is_active() return self._conn is not None and self._started.is_set() and not self._stopped.is_set()
@property @property
def local_tunnel_port(self) -> int: def local_tunnel_port(self) -> int:
+4 -4
View File
@@ -49,11 +49,11 @@ class SSHAuth(QtWidgets.QDialog, Ui_diag_sshauth):
log.error(e) log.error(e)
self._in_keyring = False self._in_keyring = False
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self, self.tr("Could not save password"), self.tr( self, self.tr("Cannot save password"), self.tr(
"Could not save password to operating systems password save.\n\n" "Cannot save password to operating system's password store.\n\n"
"Maybe your operating system does not support saving passwords. " "The operating system may not support saving passwords. "
"This could be due to missing libraries or programs.\n\n" "This could be due to missing libraries or programs.\n\n"
"This is not an error of RevPi Commander." "This is not a RevPi Commander error."
) )
) )
else: else:
+4 -4
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'aclmanager.ui' # Form implementation generated from reading ui file 'aclmanager.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -137,15 +137,15 @@ class Ui_diag_aclmanager(object):
def retranslateUi(self, diag_aclmanager): def retranslateUi(self, diag_aclmanager):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_aclmanager.setWindowTitle(_translate("diag_aclmanager", "IP access control list")) diag_aclmanager.setWindowTitle(_translate("diag_aclmanager", "IP Access Control List"))
self.gb_acls.setTitle(_translate("diag_aclmanager", "Existing ACLs")) self.gb_acls.setTitle(_translate("diag_aclmanager", "Existing ACLs"))
item = self.tb_acls.horizontalHeaderItem(0) item = self.tb_acls.horizontalHeaderItem(0)
item.setText(_translate("diag_aclmanager", "IP Address")) item.setText(_translate("diag_aclmanager", "IP address"))
item = self.tb_acls.horizontalHeaderItem(1) item = self.tb_acls.horizontalHeaderItem(1)
item.setText(_translate("diag_aclmanager", "Access Level")) item.setText(_translate("diag_aclmanager", "Access Level"))
self.btn_edit.setText(_translate("diag_aclmanager", "&Edit")) self.btn_edit.setText(_translate("diag_aclmanager", "&Edit"))
self.btn_remove.setText(_translate("diag_aclmanager", "&Remove")) self.btn_remove.setText(_translate("diag_aclmanager", "&Remove"))
self.gb_edit.setTitle(_translate("diag_aclmanager", "Add / Edit access entry")) self.gb_edit.setTitle(_translate("diag_aclmanager", "Add/Edit Access Entry"))
self.btn_clear.setText(_translate("diag_aclmanager", "Clear fields")) self.btn_clear.setText(_translate("diag_aclmanager", "Clear fields"))
self.btn_add.setText(_translate("diag_aclmanager", "&Save entry")) self.btn_add.setText(_translate("diag_aclmanager", "&Save entry"))
self.lbl_ip.setText(_translate("diag_aclmanager", "IP address:")) self.lbl_ip.setText(_translate("diag_aclmanager", "IP address:"))
+9 -9
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'avahisearch.ui' # Form implementation generated from reading ui file 'avahisearch.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -84,25 +84,25 @@ class Ui_diag_search(object):
def retranslateUi(self, diag_search): def retranslateUi(self, diag_search):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_search.setWindowTitle(_translate("diag_search", "Search Revolution Pi devices")) diag_search.setWindowTitle(_translate("diag_search", "RevPi device search"))
self.lbl_search.setText(_translate("diag_search", "Searching for Revolution Pi devices in your network...")) self.lbl_search.setText(_translate("diag_search", "Searching for RevPi devices on the network"))
self.btn_restart.setToolTip(_translate("diag_search", "Restart search")) self.btn_restart.setToolTip(_translate("diag_search", "Restart search"))
self.tb_revpi.setSortingEnabled(True) self.tb_revpi.setSortingEnabled(True)
item = self.tb_revpi.horizontalHeaderItem(0) item = self.tb_revpi.horizontalHeaderItem(0)
item.setText(_translate("diag_search", "Zero-conf name")) item.setText(_translate("diag_search", "ZeroConf name"))
item = self.tb_revpi.horizontalHeaderItem(1) item = self.tb_revpi.horizontalHeaderItem(1)
item.setText(_translate("diag_search", "IP address")) item.setText(_translate("diag_search", "IP address"))
self.btn_connect.setText(_translate("diag_search", "&Connect to Revolution Pi")) self.btn_connect.setText(_translate("diag_search", "&Connect to RevPi"))
self.btn_save.setText(_translate("diag_search", "&Save connection")) self.btn_save.setText(_translate("diag_search", "&Save connection"))
self.act_copy_host.setText(_translate("diag_search", "Copy host name")) self.act_copy_host.setText(_translate("diag_search", "Copy host name"))
self.act_copy_ip.setText(_translate("diag_search", "Copy IP address")) self.act_copy_ip.setText(_translate("diag_search", "Copy IP address"))
self.act_open_pictory.setText(_translate("diag_search", "Open piCtory")) self.act_open_pictory.setText(_translate("diag_search", "Open PiCtory"))
self.act_connect_ssh.setText(_translate("diag_search", "Connect via SSH (recommended)")) self.act_connect_ssh.setText(_translate("diag_search", "Connect via SSH (recommended)"))
self.act_connect_ssh.setToolTip(_translate("diag_search", "Establish a connection via encrypted SSH tunnel")) self.act_connect_ssh.setToolTip(_translate("diag_search", "Connect via an encrypted SSH tunnel."))
self.act_connect_xmlrpc.setText(_translate("diag_search", "Connect via XML-RPC")) self.act_connect_xmlrpc.setText(_translate("diag_search", "Connect via XML-RPC"))
self.act_connect_xmlrpc.setToolTip(_translate("diag_search", "You have to configure your Revolution Pi to accept this connections")) self.act_connect_xmlrpc.setToolTip(_translate("diag_search", "Enable these connections on RevPi."))
self.act_connect.setText(_translate("diag_search", "Connect")) self.act_connect.setText(_translate("diag_search", "Connect"))
self.act_connect.setToolTip(_translate("diag_search", "Connect to Revoluton Pi")) self.act_connect.setToolTip(_translate("diag_search", "Connect to RevPi"))
from . import ressources_rc from . import ressources_rc
+2 -2
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'backgroundworker.ui' # Form implementation generated from reading ui file 'backgroundworker.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -19,7 +19,7 @@ class Ui_diag_backgroundworker(object):
self.verticalLayout = QtWidgets.QVBoxLayout(diag_backgroundworker) self.verticalLayout = QtWidgets.QVBoxLayout(diag_backgroundworker)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.lbl_status = QtWidgets.QLabel(diag_backgroundworker) self.lbl_status = QtWidgets.QLabel(diag_backgroundworker)
self.lbl_status.setText("Status message...") self.lbl_status.setText("Status message")
self.lbl_status.setObjectName("lbl_status") self.lbl_status.setObjectName("lbl_status")
self.verticalLayout.addWidget(self.lbl_status) self.verticalLayout.addWidget(self.lbl_status)
self.pgb_status = QtWidgets.QProgressBar(diag_backgroundworker) self.pgb_status = QtWidgets.QProgressBar(diag_backgroundworker)
+12 -12
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'debugcontrol.ui' # Form implementation generated from reading ui file 'debugcontrol.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -65,21 +65,21 @@ class Ui_wid_debugcontrol(object):
def retranslateUi(self, wid_debugcontrol): def retranslateUi(self, wid_debugcontrol):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
self.gb_devices.setTitle(_translate("wid_debugcontrol", "Revolution Pi devices")) self.gb_devices.setTitle(_translate("wid_debugcontrol", "RevPi Devices"))
self.cbx_stay_on_top.setText(_translate("wid_debugcontrol", "Open to stay on top")) self.cbx_stay_on_top.setText(_translate("wid_debugcontrol", "Keep window on top"))
self.gb_control.setTitle(_translate("wid_debugcontrol", "IO Control")) self.gb_control.setTitle(_translate("wid_debugcontrol", "I/O Control"))
self.btn_read_io.setToolTip(_translate("wid_debugcontrol", "Read all IO values and discard local changes (F4)\n" self.btn_read_io.setToolTip(_translate("wid_debugcontrol", "Read all I/O values and discard local changes (F4).\n"
"\n" "\n"
"Hold this button pressed and it will refresh the IOs every 200 ms.")) "Hold this button to refresh the I/Os every 200 ms."))
self.btn_read_io.setText(_translate("wid_debugcontrol", "Read &all IO values")) self.btn_read_io.setText(_translate("wid_debugcontrol", "Read &all I/O values"))
self.btn_refresh_io.setToolTip(_translate("wid_debugcontrol", "Refresh all IO values which are locally not changed (F5)\n" self.btn_refresh_io.setToolTip(_translate("wid_debugcontrol", "Refresh all I/O values that have not been modified locally (F5).\n"
"\n" "\n"
"Hold this button pressed and it will refresh the IOs every 200 ms.")) "Hold this button to refresh the I/Os every 200 ms."))
self.btn_refresh_io.setText(_translate("wid_debugcontrol", "&Refresh unchanged IOs")) self.btn_refresh_io.setText(_translate("wid_debugcontrol", "&Refresh unchanged I/Os"))
self.btn_write_o.setToolTip(_translate("wid_debugcontrol", "Write locally changed output values to process image (F6)")) self.btn_write_o.setToolTip(_translate("wid_debugcontrol", "Write locally modified output values to process image (F6)."))
self.btn_write_o.setText(_translate("wid_debugcontrol", "&Write changed outputs")) self.btn_write_o.setText(_translate("wid_debugcontrol", "&Write changed outputs"))
self.cbx_refresh.setText(_translate("wid_debugcontrol", "&Auto refresh values")) self.cbx_refresh.setText(_translate("wid_debugcontrol", "&Auto refresh values"))
self.cbx_write.setText(_translate("wid_debugcontrol", "and write outputs")) self.cbx_write.setText(_translate("wid_debugcontrol", "Write outputs"))
if __name__ == "__main__": if __name__ == "__main__":
+1 -1
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'debugios.ui' # Form implementation generated from reading ui file 'debugios.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
+5 -5
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'files.ui' # Form implementation generated from reading ui file 'files.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -169,17 +169,17 @@ class Ui_win_files(object):
def retranslateUi(self, win_files): def retranslateUi(self, win_files):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
win_files.setWindowTitle(_translate("win_files", "File manager")) win_files.setWindowTitle(_translate("win_files", "File Manager"))
self.gb_select_local.setTitle(_translate("win_files", "Local computer")) self.gb_select_local.setTitle(_translate("win_files", "Local Computer"))
self.lbl_select_local.setText(_translate("win_files", "Path to development root:")) self.lbl_select_local.setText(_translate("win_files", "Path to development root:"))
self.btn_select_local.setToolTip(_translate("win_files", "Open developer root directory")) self.btn_select_local.setToolTip(_translate("win_files", "Open developer root directory"))
self.btn_refresh_local.setToolTip(_translate("win_files", "Reload file list")) self.btn_refresh_local.setToolTip(_translate("win_files", "Reload file list"))
self.tree_files_local.setSortingEnabled(True) self.tree_files_local.setSortingEnabled(True)
self.gb_select_revpi.setTitle(_translate("win_files", "Revolution Pi")) self.gb_select_revpi.setTitle(_translate("win_files", "RevPi"))
self.lbl_select_revpi.setText(_translate("win_files", "RevPiPyLoad working directory:")) self.lbl_select_revpi.setText(_translate("win_files", "RevPiPyLoad working directory:"))
self.btn_refresh_revpi.setToolTip(_translate("win_files", "Reload file list")) self.btn_refresh_revpi.setToolTip(_translate("win_files", "Reload file list"))
self.tree_files_revpi.setSortingEnabled(True) self.tree_files_revpi.setSortingEnabled(True)
self.btn_all.setText(_translate("win_files", "Stop - Upload - Start")) self.btn_all.setText(_translate("win_files", "Stop, upload, start"))
from . import ressources_rc from . import ressources_rc
+4 -4
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'mqttmanager.ui' # Form implementation generated from reading ui file 'mqttmanager.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -126,7 +126,7 @@ class Ui_diag_mqtt(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_mqtt.setWindowTitle(_translate("diag_mqtt", "MQTT settings")) diag_mqtt.setWindowTitle(_translate("diag_mqtt", "MQTT settings"))
self.gb_basetopic.setTitle(_translate("diag_mqtt", "Base topic")) self.gb_basetopic.setTitle(_translate("diag_mqtt", "Base topic"))
self.lbl_basetopic_description.setText(_translate("diag_mqtt", "The base topic is the first part of any mqtt topic, the Revolution Pi will publish. You can use any character includig \'/\' to structure the messages on your broker.\n" self.lbl_basetopic_description.setText(_translate("diag_mqtt", "Base topic is the prefix for MQTT topics published by RevPi. Use \"/\" to structure broker topics.\n"
"\n" "\n"
"For example: revpi0000/data")) "For example: revpi0000/data"))
self.lbl_basetopic.setText(_translate("diag_mqtt", "Base topic:")) self.lbl_basetopic.setText(_translate("diag_mqtt", "Base topic:"))
@@ -136,10 +136,10 @@ class Ui_diag_mqtt(object):
self.cbx_send_on_event.setText(_translate("diag_mqtt", "Send exported values immediately on value change")) self.cbx_send_on_event.setText(_translate("diag_mqtt", "Send exported values immediately on value change"))
self.lbl_topic_event.setText(_translate("diag_mqtt", "Topic: [basetopic]/event/[ioname]")) self.lbl_topic_event.setText(_translate("diag_mqtt", "Topic: [basetopic]/event/[ioname]"))
self.gb_write_outputs.setTitle(_translate("diag_mqtt", "Set outputs")) self.gb_write_outputs.setTitle(_translate("diag_mqtt", "Set outputs"))
self.lbl_write_outputs.setText(_translate("diag_mqtt", "The Revolution Pi will subscribe a topic on which your mqtt client can publish messages with the new io value as payload.\n" self.lbl_write_outputs.setText(_translate("diag_mqtt", "RevPi subscribes to an MQTT topic for setting output values. Publish the new I/O value as payload.\n"
"\n" "\n"
"Publish values with topic: [basetopic]/set/[outputname]")) "Publish values with topic: [basetopic]/set/[outputname]"))
self.cbx_write_outputs.setText(_translate("diag_mqtt", "Allow MQTT to to set outputs on Revolution Pi")) self.cbx_write_outputs.setText(_translate("diag_mqtt", "Allow MQTT to set outputs on RevPi"))
self.gb_broker.setTitle(_translate("diag_mqtt", "Broker settings")) self.gb_broker.setTitle(_translate("diag_mqtt", "Broker settings"))
self.lbl_broker_address.setText(_translate("diag_mqtt", "Broker address:")) self.lbl_broker_address.setText(_translate("diag_mqtt", "Broker address:"))
self.lbl_port.setText(_translate("diag_mqtt", "Broker port:")) self.lbl_port.setText(_translate("diag_mqtt", "Broker port:"))
+4 -4
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'oss_licenses.ui' # Form implementation generated from reading ui file 'oss_licenses.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -59,14 +59,14 @@ class Ui_diag_oss_licenses(object):
def retranslateUi(self, diag_oss_licenses): def retranslateUi(self, diag_oss_licenses):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_oss_licenses.setWindowTitle(_translate("diag_oss_licenses", "Open-Source licenses")) diag_oss_licenses.setWindowTitle(_translate("diag_oss_licenses", "Open source licenses"))
self.tb_oss_licenses.setSortingEnabled(True) self.tb_oss_licenses.setSortingEnabled(True)
item = self.tb_oss_licenses.horizontalHeaderItem(0) item = self.tb_oss_licenses.horizontalHeaderItem(0)
item.setText(_translate("diag_oss_licenses", "Software")) item.setText(_translate("diag_oss_licenses", "Software"))
item = self.tb_oss_licenses.horizontalHeaderItem(1) item = self.tb_oss_licenses.horizontalHeaderItem(1)
item.setText(_translate("diag_oss_licenses", "License")) item.setText(_translate("diag_oss_licenses", "License"))
self.action_start.setText(_translate("diag_oss_licenses", "More licenses...")) self.action_start.setText(_translate("diag_oss_licenses", "More licenses"))
self.action_start.setToolTip(_translate("diag_oss_licenses", "Show more open-source software licenses")) self.action_start.setToolTip(_translate("diag_oss_licenses", "Show more open source software licenses"))
if __name__ == "__main__": if __name__ == "__main__":
+6 -6
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'revpicommander.ui' # Form implementation generated from reading ui file 'revpicommander.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -177,17 +177,17 @@ class Ui_win_revpicommander(object):
self.men_plc.setTitle(_translate("win_revpicommander", "&PLC")) self.men_plc.setTitle(_translate("win_revpicommander", "&PLC"))
self.men_connections.setTitle(_translate("win_revpicommander", "&Connections")) self.men_connections.setTitle(_translate("win_revpicommander", "&Connections"))
self.act_connections.setText(_translate("win_revpicommander", "&Connections...")) self.act_connections.setText(_translate("win_revpicommander", "&Connections..."))
self.act_search.setText(_translate("win_revpicommander", "&Search Revolution Pi...")) self.act_search.setText(_translate("win_revpicommander", "&Search RevPi..."))
self.act_quit.setText(_translate("win_revpicommander", "&Quit")) self.act_quit.setText(_translate("win_revpicommander", "&Quit"))
self.act_webpage.setText(_translate("win_revpicommander", "Visit &webpage...")) self.act_webpage.setText(_translate("win_revpicommander", "Visit &website"))
self.act_info.setText(_translate("win_revpicommander", "&Info...")) self.act_info.setText(_translate("win_revpicommander", "&Info"))
self.act_logs.setText(_translate("win_revpicommander", "PLC &logs...")) self.act_logs.setText(_translate("win_revpicommander", "PLC &logs..."))
self.act_options.setText(_translate("win_revpicommander", "PLC &options...")) self.act_options.setText(_translate("win_revpicommander", "PLC &options..."))
self.act_program.setText(_translate("win_revpicommander", "PLC progra&m...")) self.act_program.setText(_translate("win_revpicommander", "PLC progra&m..."))
self.act_developer.setText(_translate("win_revpicommander", "PLC de&veloper...")) self.act_developer.setText(_translate("win_revpicommander", "PLC de&veloper..."))
self.act_pictory.setText(_translate("win_revpicommander", "piCtory configuraiton...")) self.act_pictory.setText(_translate("win_revpicommander", "PiCtory configuration"))
self.act_disconnect.setText(_translate("win_revpicommander", "&Disconnect")) self.act_disconnect.setText(_translate("win_revpicommander", "&Disconnect"))
self.act_reset.setText(_translate("win_revpicommander", "Reset driver...")) self.act_reset.setText(_translate("win_revpicommander", "Reset driver"))
self.act_simulator.setText(_translate("win_revpicommander", "RevPi si&mulator...")) self.act_simulator.setText(_translate("win_revpicommander", "RevPi si&mulator..."))
from . import ressources_rc from . import ressources_rc
+5 -6
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'revpiinfo.ui' # Form implementation generated from reading ui file 'revpiinfo.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -75,7 +75,7 @@ class Ui_diag_revpiinfo(object):
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem, 5, 0, 1, 1) self.gridLayout.addItem(spacerItem, 5, 0, 1, 1)
self.lbl_link = QtWidgets.QLabel(diag_revpiinfo) self.lbl_link = QtWidgets.QLabel(diag_revpiinfo)
self.lbl_link.setText("<html><head/><body><p><a href=\"https://revpimodio.org/\"><span style=\" text-decoration: underline; color:#0000ff;\">https://revpimodio.org/</span></a></p></body></html>") self.lbl_link.setText("<html><head/><body><p><a href=\"https://revpimodio2.readthedocs.io/en/latest/\"><span style=\" text-decoration: underline; color:#0000ff;\">https://revpimodio2.readthedocs.io/en/latest/</span></a></p></body></html>")
self.lbl_link.setOpenExternalLinks(True) self.lbl_link.setOpenExternalLinks(True)
self.lbl_link.setObjectName("lbl_link") self.lbl_link.setObjectName("lbl_link")
self.gridLayout.addWidget(self.lbl_link, 6, 0, 1, 2) self.gridLayout.addWidget(self.lbl_link, 6, 0, 1, 2)
@@ -87,13 +87,12 @@ class Ui_diag_revpiinfo(object):
def retranslateUi(self, diag_revpiinfo): def retranslateUi(self, diag_revpiinfo):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_revpiinfo.setWindowTitle(_translate("diag_revpiinfo", "Program information")) diag_revpiinfo.setWindowTitle(_translate("diag_revpiinfo", "Program Information"))
self.lbl_head.setText(_translate("diag_revpiinfo", "RevPi Python PLC - Commander")) self.lbl_head.setText(_translate("diag_revpiinfo", "RevPi Commander (Python/PLC)"))
self.lbl_lbl_version_pyload.setText(_translate("diag_revpiinfo", "RevPiPyLoad version on RevPi:")) self.lbl_lbl_version_pyload.setText(_translate("diag_revpiinfo", "RevPiPyLoad version on RevPi:"))
self.lbl_lbl_version_control.setText(_translate("diag_revpiinfo", "Version:")) self.lbl_lbl_version_control.setText(_translate("diag_revpiinfo", "Version:"))
self.lbl_info.setText(_translate("diag_revpiinfo", "RevPiModIO, RevPiPyLoad and RevPiPyControl are community driven projects. They are all free and open source software.\n" self.lbl_info.setText(_translate("diag_revpiinfo", "RevPiModIO, RevPiPyLoad and RevPiPyControl are community driven projects. They are all free and open source software.\n"
"All of them comes with ABSOLUTELY NO WARRANTY, to the extent permitted by\n" "All of them come with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.\n"
"applicable law.\n"
"\n" "\n"
"(c) Sven Sager, License: GPLv2")) "(c) Sven Sager, License: GPLv2"))
+5 -5
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'revpilogfile.ui' # Form implementation generated from reading ui file 'revpilogfile.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -79,13 +79,13 @@ class Ui_win_revpilogfile(object):
def retranslateUi(self, win_revpilogfile): def retranslateUi(self, win_revpilogfile):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
win_revpilogfile.setWindowTitle(_translate("win_revpilogfile", "RevPi Python PLC Logfiles")) win_revpilogfile.setWindowTitle(_translate("win_revpilogfile", "RevPi Python PLC Log Files"))
self.cbx_stay_on_top.setText(_translate("win_revpilogfile", "Stay on top of all windows")) self.cbx_stay_on_top.setText(_translate("win_revpilogfile", "Stay on top of all windows"))
self.cbx_wrap.setText(_translate("win_revpilogfile", "Linewrap")) self.cbx_wrap.setText(_translate("win_revpilogfile", "Line wrap"))
self.lbl_daemon.setText(_translate("win_revpilogfile", "RevPiPyLoad - Logfile")) self.lbl_daemon.setText(_translate("win_revpilogfile", "RevPiPyLoad Log File"))
self.btn_daemon.setText(_translate("win_revpilogfile", "Clear view")) self.btn_daemon.setText(_translate("win_revpilogfile", "Clear view"))
self.btn_app.setText(_translate("win_revpilogfile", "Clear view")) self.btn_app.setText(_translate("win_revpilogfile", "Clear view"))
self.lbl_app.setText(_translate("win_revpilogfile", "Python PLC program - Logfile")) self.lbl_app.setText(_translate("win_revpilogfile", "Python PLC Program Log File"))
if __name__ == "__main__": if __name__ == "__main__":
+15 -15
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'revpioption.ui' # Form implementation generated from reading ui file 'revpioption.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -123,34 +123,34 @@ class Ui_diag_options(object):
def retranslateUi(self, diag_options): def retranslateUi(self, diag_options):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_options.setWindowTitle(_translate("diag_options", "RevPi Python PLC Options")) diag_options.setWindowTitle(_translate("diag_options", "RevPi Python PLC Options"))
self.gb_plc.setTitle(_translate("diag_options", "Start / Stop behavior of PLC program")) self.gb_plc.setTitle(_translate("diag_options", "PLC Start/Stop Behavior"))
self.lbl_replace_io.setText(_translate("diag_options", "Replace IO file:")) self.lbl_replace_io.setText(_translate("diag_options", "Replace I/O file:"))
self.cbx_zeroonerror.setText(_translate("diag_options", "... after exception and errors")) self.cbx_zeroonerror.setText(_translate("diag_options", "after exceptions or errors"))
self.cbx_autostart.setText(_translate("diag_options", "Start PLC program automatically")) self.cbx_autostart.setText(_translate("diag_options", "Start PLC program automatically"))
self.cbb_reset_driver_action.setItemText(0, _translate("diag_options", "Do nothing")) self.cbb_reset_driver_action.setItemText(0, _translate("diag_options", "Do nothing"))
self.cbb_reset_driver_action.setItemText(1, _translate("diag_options", "Restart after piCtory changed")) self.cbb_reset_driver_action.setItemText(1, _translate("diag_options", "Restart after PiCtory changes"))
self.cbb_reset_driver_action.setItemText(2, _translate("diag_options", "Always restart the PLC program")) self.cbb_reset_driver_action.setItemText(2, _translate("diag_options", "Always restart the PLC program"))
self.lbl_reset_driver_action.setText(_translate("diag_options", "Driver reset action:")) self.lbl_reset_driver_action.setText(_translate("diag_options", "Driver reset action:"))
self.lbl_plc_zero.setText(_translate("diag_options", "Set process image to NULL if program terminates...")) self.lbl_plc_zero.setText(_translate("diag_options", "Set process image to NULL if the program terminates"))
self.cbb_replace_io.setItemText(0, _translate("diag_options", "Do not use replace io file")) self.cbb_replace_io.setItemText(0, _translate("diag_options", "Do not replace I/O file"))
self.cbb_replace_io.setItemText(1, _translate("diag_options", "Use static file from RevPiPyLoad")) self.cbb_replace_io.setItemText(1, _translate("diag_options", "Use static file from RevPiPyLoad"))
self.cbb_replace_io.setItemText(2, _translate("diag_options", "Use dynamic file from work directory")) self.cbb_replace_io.setItemText(2, _translate("diag_options", "Use dynamic file from work directory"))
self.cbb_replace_io.setItemText(3, _translate("diag_options", "Give own path and filename")) self.cbb_replace_io.setItemText(3, _translate("diag_options", "Use custom path and file name"))
self.cbx_zeroonexit.setText(_translate("diag_options", "... sucessfully without error")) self.cbx_zeroonexit.setText(_translate("diag_options", "without errors"))
self.lbl_plc_delay.setText(_translate("diag_options", "Restart delay in seconds:")) self.lbl_plc_delay.setText(_translate("diag_options", "Restart delay in seconds:"))
self.cbx_autoreload.setText(_translate("diag_options", "Restart PLC program after exit or crash")) self.cbx_autoreload.setText(_translate("diag_options", "Restart PLC program after exit or crash"))
self.lbl_lbl_reset_driver_action.setText(_translate("diag_options", "PLC program behavior after piCtory driver reset clicked")) self.lbl_lbl_reset_driver_action.setText(_translate("diag_options", "PLC program behavior after PiCtory driver reset"))
self.gb_server.setTitle(_translate("diag_options", "RevPiPyLoad server services")) self.gb_server.setTitle(_translate("diag_options", "RevPiPyLoad Server Services"))
self.btn_aclplcserver.setText(_translate("diag_options", "Edit ACL")) self.btn_aclplcserver.setText(_translate("diag_options", "Edit ACL"))
self.cbx_mqtt.setText(_translate("diag_options", "MQTT process image publisher")) self.cbx_mqtt.setText(_translate("diag_options", "MQTT process image publisher"))
self.cbx_plcserver.setText(_translate("diag_options", "Start RevPi piControl server")) self.cbx_plcserver.setText(_translate("diag_options", "Start piControl server"))
self.lbl_server_status.setText(_translate("diag_options", "status")) self.lbl_server_status.setText(_translate("diag_options", "status"))
self.lbl_lbl_server_status.setText(_translate("diag_options", "piControl server is:")) self.lbl_lbl_server_status.setText(_translate("diag_options", "piControl server:"))
self.lbl_mqtt_status.setText(_translate("diag_options", "status")) self.lbl_mqtt_status.setText(_translate("diag_options", "status"))
self.lbl_lbl_mqtt_status.setText(_translate("diag_options", "MQTT publish service is:")) self.lbl_lbl_mqtt_status.setText(_translate("diag_options", "MQTT publish service:"))
self.btn_mqtt.setText(_translate("diag_options", "Settings")) self.btn_mqtt.setText(_translate("diag_options", "Settings"))
self.btn_aclxmlrpc.setText(_translate("diag_options", "Edit ACL")) self.btn_aclxmlrpc.setText(_translate("diag_options", "Edit ACL"))
self.cbx_xmlrpc.setText(_translate("diag_options", "Activate XML-RPC for RevPiCommander")) self.cbx_xmlrpc.setText(_translate("diag_options", "Activate XML-RPC for RevPi Commander"))
if __name__ == "__main__": if __name__ == "__main__":
+20 -13
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'revpiplclist.ui' # Form implementation generated from reading ui file 'revpiplclist.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -37,7 +37,7 @@ class Ui_diag_connections(object):
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txt_address) self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.txt_address)
self.lbl_port = QtWidgets.QLabel(self.tab_connection) self.lbl_port = QtWidgets.QLabel(self.tab_connection)
self.lbl_port.setObjectName("lbl_port") self.lbl_port.setObjectName("lbl_port")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_port) self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_port)
self.sbx_port = QtWidgets.QSpinBox(self.tab_connection) self.sbx_port = QtWidgets.QSpinBox(self.tab_connection)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@@ -48,10 +48,10 @@ class Ui_diag_connections(object):
self.sbx_port.setMaximum(65535) self.sbx_port.setMaximum(65535)
self.sbx_port.setProperty("value", 55123) self.sbx_port.setProperty("value", 55123)
self.sbx_port.setObjectName("sbx_port") self.sbx_port.setObjectName("sbx_port")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.sbx_port) self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.sbx_port)
self.lbl_timeout = QtWidgets.QLabel(self.tab_connection) self.lbl_timeout = QtWidgets.QLabel(self.tab_connection)
self.lbl_timeout.setObjectName("lbl_timeout") self.lbl_timeout.setObjectName("lbl_timeout")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_timeout) self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.lbl_timeout)
self.sbx_timeout = QtWidgets.QSpinBox(self.tab_connection) self.sbx_timeout = QtWidgets.QSpinBox(self.tab_connection)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@@ -61,17 +61,23 @@ class Ui_diag_connections(object):
self.sbx_timeout.setMinimum(5) self.sbx_timeout.setMinimum(5)
self.sbx_timeout.setMaximum(30) self.sbx_timeout.setMaximum(30)
self.sbx_timeout.setObjectName("sbx_timeout") self.sbx_timeout.setObjectName("sbx_timeout")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.sbx_timeout) self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.sbx_timeout)
self.lbl_folder = QtWidgets.QLabel(self.tab_connection) self.lbl_folder = QtWidgets.QLabel(self.tab_connection)
self.lbl_folder.setObjectName("lbl_folder") self.lbl_folder.setObjectName("lbl_folder")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.lbl_folder) self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.lbl_folder)
self.cbb_folder = QtWidgets.QComboBox(self.tab_connection) self.cbb_folder = QtWidgets.QComboBox(self.tab_connection)
self.cbb_folder.setEditable(True) self.cbb_folder.setEditable(True)
self.cbb_folder.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) self.cbb_folder.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
self.cbb_folder.setObjectName("cbb_folder") self.cbb_folder.setObjectName("cbb_folder")
self.cbb_folder.addItem("") self.cbb_folder.addItem("")
self.cbb_folder.setItemText(0, "") self.cbb_folder.setItemText(0, "")
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.cbb_folder) self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.cbb_folder)
self.lbl_local_socket = QtWidgets.QLabel(self.tab_connection)
self.lbl_local_socket.setObjectName("lbl_local_socket")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_local_socket)
self.cbx_local_socket = QtWidgets.QCheckBox(self.tab_connection)
self.cbx_local_socket.setObjectName("cbx_local_socket")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.cbx_local_socket)
self.tab_properties.addTab(self.tab_connection, "") self.tab_properties.addTab(self.tab_connection, "")
self.tab_ssh = QtWidgets.QWidget() self.tab_ssh = QtWidgets.QWidget()
self.tab_ssh.setObjectName("tab_ssh") self.tab_ssh.setObjectName("tab_ssh")
@@ -155,19 +161,20 @@ class Ui_diag_connections(object):
def retranslateUi(self, diag_connections): def retranslateUi(self, diag_connections):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_connections.setWindowTitle(_translate("diag_connections", "Revolution Pi connections")) diag_connections.setWindowTitle(_translate("diag_connections", "RevPi Connections"))
self.lbl_name.setText(_translate("diag_connections", "Display name:")) self.lbl_name.setText(_translate("diag_connections", "Display name:"))
self.lbl_address.setText(_translate("diag_connections", "Address (DNS/IP):")) self.lbl_address.setText(_translate("diag_connections", "Address (DNS/IP/Socket):"))
self.lbl_port.setText(_translate("diag_connections", "Port (Default {0}):")) self.lbl_port.setText(_translate("diag_connections", "Port (default {0}):"))
self.lbl_timeout.setText(_translate("diag_connections", "Connection timeout:")) self.lbl_timeout.setText(_translate("diag_connections", "Connection timeout:"))
self.sbx_timeout.setSuffix(_translate("diag_connections", " sec.")) self.sbx_timeout.setSuffix(_translate("diag_connections", " s"))
self.lbl_folder.setText(_translate("diag_connections", "Sub folder:")) self.lbl_folder.setText(_translate("diag_connections", "Subfolder:"))
self.lbl_local_socket.setText(_translate("diag_connections", "Use default local socket:"))
self.tab_properties.setTabText(self.tab_properties.indexOf(self.tab_connection), _translate("diag_connections", "Connection")) self.tab_properties.setTabText(self.tab_properties.indexOf(self.tab_connection), _translate("diag_connections", "Connection"))
self.lbl_ssh_use_tunnel.setText(_translate("diag_connections", "Connect over SSH tunnel:")) self.lbl_ssh_use_tunnel.setText(_translate("diag_connections", "Connect over SSH tunnel:"))
self.lbl_ssh_port.setText(_translate("diag_connections", "SSH port:")) self.lbl_ssh_port.setText(_translate("diag_connections", "SSH port:"))
self.lbl_ssh_user.setText(_translate("diag_connections", "SSH user name:")) self.lbl_ssh_user.setText(_translate("diag_connections", "SSH user name:"))
self.tab_properties.setTabText(self.tab_properties.indexOf(self.tab_ssh), _translate("diag_connections", "Over SSH")) self.tab_properties.setTabText(self.tab_properties.indexOf(self.tab_ssh), _translate("diag_connections", "Over SSH"))
self.tre_connections.headerItem().setText(0, _translate("diag_connections", "Connection name")) self.tre_connections.headerItem().setText(0, _translate("diag_connections", "Connection Name"))
self.tre_connections.headerItem().setText(1, _translate("diag_connections", "Address")) self.tre_connections.headerItem().setText(1, _translate("diag_connections", "Address"))
from . import ressources_rc from . import ressources_rc
+14 -14
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'revpiprogram.ui' # Form implementation generated from reading ui file 'revpiprogram.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -112,27 +112,27 @@ class Ui_diag_program(object):
def retranslateUi(self, diag_program): def retranslateUi(self, diag_program):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_program.setWindowTitle(_translate("diag_program", "PLC program")) diag_program.setWindowTitle(_translate("diag_program", "PLC Program"))
self.gb_plc.setTitle(_translate("diag_program", "PLC program")) self.gb_plc.setTitle(_translate("diag_program", "PLC Program"))
self.lbl_plcarguments.setText(_translate("diag_program", "Program arguments:")) self.lbl_plcarguments.setText(_translate("diag_program", "Arguments:"))
self.lbl_plcprogram_watchdog.setText(_translate("diag_program", "Software watchdog (0=disabled):")) self.lbl_plcprogram_watchdog.setText(_translate("diag_program", "Software watchdog (0 = disabled):"))
self.cbx_plcworkdir_set_uid.setText(_translate("diag_program", "Set write permissions for plc program to workdirectory")) self.cbx_plcworkdir_set_uid.setText(_translate("diag_program", "Set write permissions for PLC program working directory"))
self.lbl_plcprogram.setText(_translate("diag_program", "Python PLC start program:")) self.lbl_plcprogram.setText(_translate("diag_program", "Python PLC start program:"))
self.sbx_plcprogram_watchdog.setSuffix(_translate("diag_program", " sec.")) self.sbx_plcprogram_watchdog.setSuffix(_translate("diag_program", " s"))
self.cb_transfair.setTitle(_translate("diag_program", "Transfair PLC program")) self.cb_transfair.setTitle(_translate("diag_program", "Transfer PLC program"))
self.cbb_format.setItemText(0, _translate("diag_program", "ZIP archive")) self.cbb_format.setItemText(0, _translate("diag_program", "ZIP archive"))
self.cbb_format.setItemText(1, _translate("diag_program", "TGZ archive")) self.cbb_format.setItemText(1, _translate("diag_program", "TGZ archive"))
self.btn_program_upload.setText(_translate("diag_program", "Upload")) self.btn_program_upload.setText(_translate("diag_program", "Upload"))
self.btn_program_download.setText(_translate("diag_program", "Download")) self.btn_program_download.setText(_translate("diag_program", "Download"))
self.lbl_format.setText(_translate("diag_program", "Transfair format:")) self.lbl_format.setText(_translate("diag_program", "Transfer format:"))
self.cbx_pictory.setText(_translate("diag_program", "Including piCtory configuration")) self.cbx_pictory.setText(_translate("diag_program", "Include PiCtory configuration"))
self.cbx_clear.setText(_translate("diag_program", "Remove all files on Revolution Pi before upload")) self.cbx_clear.setText(_translate("diag_program", "Remove all files on RevPi before upload"))
self.gb_control.setTitle(_translate("diag_program", "Control files")) self.gb_control.setTitle(_translate("diag_program", "Control Files"))
self.btn_procimg_download.setText(_translate("diag_program", "Download")) self.btn_procimg_download.setText(_translate("diag_program", "Download"))
self.btn_pictory_download.setText(_translate("diag_program", "Download")) self.btn_pictory_download.setText(_translate("diag_program", "Download"))
self.btn_pictory_upload.setText(_translate("diag_program", "Upload")) self.btn_pictory_upload.setText(_translate("diag_program", "Upload"))
self.lbl_pictory.setText(_translate("diag_program", "piCtory configuraiton")) self.lbl_pictory.setText(_translate("diag_program", "PiCtory configuration"))
self.lbl_procimg.setText(_translate("diag_program", "Process image from piControl0")) self.lbl_procimg.setText(_translate("diag_program", "Process image from piControl"))
if __name__ == "__main__": if __name__ == "__main__":
+11 -11
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'simulator.ui' # Form implementation generated from reading ui file 'simulator.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -108,22 +108,22 @@ class Ui_diag_simulator(object):
def retranslateUi(self, diag_simulator): def retranslateUi(self, diag_simulator):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_simulator.setWindowTitle(_translate("diag_simulator", "piControl simulator")) diag_simulator.setWindowTitle(_translate("diag_simulator", "piControl Simulator"))
self.gb_settings.setTitle(_translate("diag_simulator", "Simulator settings")) self.gb_settings.setTitle(_translate("diag_simulator", "Simulator Settings"))
self.lbl_history.setText(_translate("diag_simulator", "Last used:")) self.lbl_history.setText(_translate("diag_simulator", "Last used:"))
self.lbl_configrsc.setText(_translate("diag_simulator", "piCtory file:")) self.lbl_configrsc.setText(_translate("diag_simulator", "PiCtory file:"))
self.btn_configrsc.setText(_translate("diag_simulator", "select...")) self.btn_configrsc.setText(_translate("diag_simulator", "Select"))
self.lbl_procimg.setText(_translate("diag_simulator", "Process image:")) self.lbl_procimg.setText(_translate("diag_simulator", "Process image:"))
self.lbl_stop.setText(_translate("diag_simulator", "Stop action:")) self.lbl_stop.setText(_translate("diag_simulator", "Stop action:"))
self.lbl_restart.setText(_translate("diag_simulator", "Restart action:")) self.lbl_restart.setText(_translate("diag_simulator", "Restart action:"))
self.cbx_stop_remove.setText(_translate("diag_simulator", "Remove process image file")) self.cbx_stop_remove.setText(_translate("diag_simulator", "Remove process image file"))
self.rb_restart_pictory.setText(_translate("diag_simulator", "Restore piCtory default values")) self.rb_restart_pictory.setText(_translate("diag_simulator", "Restore PiCtory default values"))
self.rb_restart_zero.setText(_translate("diag_simulator", "Reset everything to ZERO")) self.rb_restart_zero.setText(_translate("diag_simulator", "Reset all values to NULL"))
self.gb_info.setTitle(_translate("diag_simulator", "RevPiModIO integration")) self.gb_info.setTitle(_translate("diag_simulator", "RevPiModIO Integration"))
self.lbl_info.setText(_translate("diag_simulator", "You can work with this simulator if you call RevPiModIO with this additional parameters:")) self.lbl_info.setText(_translate("diag_simulator", "To use this simulator, call RevPiModIO with the following additional parameters:"))
self.btn_start_pictory.setText(_translate("diag_simulator", "Start with piCtory default values")) self.btn_start_pictory.setText(_translate("diag_simulator", "Start with PiCtory default values"))
self.btn_start_empty.setText(_translate("diag_simulator", "Start with empty process image")) self.btn_start_empty.setText(_translate("diag_simulator", "Start with empty process image"))
self.btn_start_nochange.setText(_translate("diag_simulator", "Start without changing actual process image")) self.btn_start_nochange.setText(_translate("diag_simulator", "Start without changing the current process image"))
if __name__ == "__main__": if __name__ == "__main__":
+5 -5
View File
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'sshauth.ui' # Form implementation generated from reading ui file 'sshauth.ui'
# #
# Created by: PyQt5 UI code generator 5.15.9 # Created by: PyQt5 UI code generator 5.15.11
# #
# WARNING: Any manual changes made to this file will be lost when pyuic5 is # WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
@@ -64,11 +64,11 @@ class Ui_diag_sshauth(object):
def retranslateUi(self, diag_sshauth): def retranslateUi(self, diag_sshauth):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
diag_sshauth.setWindowTitle(_translate("diag_sshauth", "SSH authentication")) diag_sshauth.setWindowTitle(_translate("diag_sshauth", "SSH authentication"))
self.lbl_username.setText(_translate("diag_sshauth", "SSH username:")) self.lbl_username.setText(_translate("diag_sshauth", "SSH user name:"))
self.lbl_password.setText(_translate("diag_sshauth", "SSH password:")) self.lbl_password.setText(_translate("diag_sshauth", "SSH password:"))
self.cbx_save_password.setToolTip(_translate("diag_sshauth", "Username and password will be saved in secured operating systems\'s password storage.")) self.cbx_save_password.setToolTip(_translate("diag_sshauth", "Save user name and password in secure password storage."))
self.cbx_save_password.setText(_translate("diag_sshauth", "Save username and password")) self.cbx_save_password.setText(_translate("diag_sshauth", "Save user name and password"))
self.lbl_info.setText(_translate("diag_sshauth", "Note: The default user for SSH is \"pi\" which differs from the web configuration. You can find the password on the sticker on the device.")) self.lbl_info.setText(_translate("diag_sshauth", "Default SSH user is \"pi\". The device password is on the RevPi housing sticker."))
if __name__ == "__main__": if __name__ == "__main__":
+3 -3
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>IP access control list</string> <string>IP Access Control List</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
@@ -51,7 +51,7 @@
</attribute> </attribute>
<column> <column>
<property name="text"> <property name="text">
<string>IP Address</string> <string>IP address</string>
</property> </property>
</column> </column>
<column> <column>
@@ -97,7 +97,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_edit"> <widget class="QGroupBox" name="gb_edit">
<property name="title"> <property name="title">
<string>Add / Edit access entry</string> <string>Add/Edit Access Entry</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0"> <item row="1" column="0">
+8 -8
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Search Revolution Pi devices</string> <string>RevPi device search</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
@@ -19,7 +19,7 @@
<item> <item>
<widget class="QLabel" name="lbl_search"> <widget class="QLabel" name="lbl_search">
<property name="text"> <property name="text">
<string>Searching for Revolution Pi devices in your network...</string> <string>Searching for RevPi devices on the network</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -85,7 +85,7 @@
</attribute> </attribute>
<column> <column>
<property name="text"> <property name="text">
<string>Zero-conf name</string> <string>ZeroConf name</string>
</property> </property>
</column> </column>
<column> <column>
@@ -98,7 +98,7 @@
<item row="2" column="0"> <item row="2" column="0">
<widget class="QPushButton" name="btn_connect"> <widget class="QPushButton" name="btn_connect">
<property name="text"> <property name="text">
<string>&amp;Connect to Revolution Pi</string> <string>&amp;Connect to RevPi</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -132,7 +132,7 @@
</action> </action>
<action name="act_open_pictory"> <action name="act_open_pictory">
<property name="text"> <property name="text">
<string>Open piCtory</string> <string>Open PiCtory</string>
</property> </property>
</action> </action>
<action name="act_connect_ssh"> <action name="act_connect_ssh">
@@ -140,7 +140,7 @@
<string>Connect via SSH (recommended)</string> <string>Connect via SSH (recommended)</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Establish a connection via encrypted SSH tunnel</string> <string>Connect via an encrypted SSH tunnel.</string>
</property> </property>
</action> </action>
<action name="act_connect_xmlrpc"> <action name="act_connect_xmlrpc">
@@ -148,7 +148,7 @@
<string>Connect via XML-RPC</string> <string>Connect via XML-RPC</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>You have to configure your Revolution Pi to accept this connections</string> <string>Enable these connections on RevPi.</string>
</property> </property>
</action> </action>
<action name="act_connect"> <action name="act_connect">
@@ -156,7 +156,7 @@
<string>Connect</string> <string>Connect</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Connect to Revoluton Pi</string> <string>Connect to RevPi</string>
</property> </property>
</action> </action>
</widget> </widget>
+1 -1
View File
@@ -17,7 +17,7 @@
<item> <item>
<widget class="QLabel" name="lbl_status"> <widget class="QLabel" name="lbl_status">
<property name="text"> <property name="text">
<string notr="true">Status message...</string> <string notr="true">Status message</string>
</property> </property>
</widget> </widget>
</item> </item>
+11 -11
View File
@@ -32,7 +32,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QGroupBox" name="gb_devices"> <widget class="QGroupBox" name="gb_devices">
<property name="title"> <property name="title">
<string>Revolution Pi devices</string> <string>RevPi Devices</string>
</property> </property>
<layout class="QVBoxLayout" name="vl_devices"/> <layout class="QVBoxLayout" name="vl_devices"/>
</widget> </widget>
@@ -40,25 +40,25 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="cbx_stay_on_top"> <widget class="QCheckBox" name="cbx_stay_on_top">
<property name="text"> <property name="text">
<string>Open to stay on top</string> <string>Keep window on top</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" rowspan="2"> <item row="0" column="1" rowspan="2">
<widget class="QGroupBox" name="gb_control"> <widget class="QGroupBox" name="gb_control">
<property name="title"> <property name="title">
<string>IO Control</string> <string>I/O Control</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QPushButton" name="btn_read_io"> <widget class="QPushButton" name="btn_read_io">
<property name="toolTip"> <property name="toolTip">
<string>Read all IO values and discard local changes (F4) <string>Read all I/O values and discard local changes (F4).
Hold this button pressed and it will refresh the IOs every 200 ms.</string> Hold this button to refresh the I/Os every 200 ms.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Read &amp;all IO values</string> <string>Read &amp;all I/O values</string>
</property> </property>
<property name="autoRepeat"> <property name="autoRepeat">
<bool>true</bool> <bool>true</bool>
@@ -74,12 +74,12 @@ Hold this button pressed and it will refresh the IOs every 200 ms.</string>
<item> <item>
<widget class="QPushButton" name="btn_refresh_io"> <widget class="QPushButton" name="btn_refresh_io">
<property name="toolTip"> <property name="toolTip">
<string>Refresh all IO values which are locally not changed (F5) <string>Refresh all I/O values that have not been modified locally (F5).
Hold this button pressed and it will refresh the IOs every 200 ms.</string> Hold this button to refresh the I/Os every 200 ms.</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Refresh unchanged IOs</string> <string>&amp;Refresh unchanged I/Os</string>
</property> </property>
<property name="autoRepeat"> <property name="autoRepeat">
<bool>true</bool> <bool>true</bool>
@@ -95,7 +95,7 @@ Hold this button pressed and it will refresh the IOs every 200 ms.</string>
<item> <item>
<widget class="QPushButton" name="btn_write_o"> <widget class="QPushButton" name="btn_write_o">
<property name="toolTip"> <property name="toolTip">
<string>Write locally changed output values to process image (F6)</string> <string>Write locally modified output values to process image (F6).</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Write changed outputs</string> <string>&amp;Write changed outputs</string>
@@ -112,7 +112,7 @@ Hold this button pressed and it will refresh the IOs every 200 ms.</string>
<item> <item>
<widget class="QCheckBox" name="cbx_write"> <widget class="QCheckBox" name="cbx_write">
<property name="text"> <property name="text">
<string>and write outputs</string> <string>Write outputs</string>
</property> </property>
</widget> </widget>
</item> </item>
+4 -4
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>File manager</string> <string>File Manager</string>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
@@ -28,7 +28,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_select_local"> <widget class="QGroupBox" name="gb_select_local">
<property name="title"> <property name="title">
<string>Local computer</string> <string>Local Computer</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0"> <layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0">
<item row="0" column="0"> <item row="0" column="0">
@@ -168,7 +168,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_select_revpi"> <widget class="QGroupBox" name="gb_select_revpi">
<property name="title"> <property name="title">
<string>Revolution Pi</string> <string>RevPi</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="1,0"> <layout class="QGridLayout" name="gridLayout_3" columnstretch="1,0">
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
@@ -328,7 +328,7 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QPushButton" name="btn_all"> <widget class="QPushButton" name="btn_all">
<property name="text"> <property name="text">
<string>Stop - Upload - Start</string> <string>Stop, upload, start</string>
</property> </property>
</widget> </widget>
</item> </item>
+3 -3
View File
@@ -29,7 +29,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>The base topic is the first part of any mqtt topic, the Revolution Pi will publish. You can use any character includig '/' to structure the messages on your broker. <string>Base topic is the prefix for MQTT topics published by RevPi. Use "/" to structure broker topics.
For example: revpi0000/data</string> For example: revpi0000/data</string>
</property> </property>
@@ -113,7 +113,7 @@ For example: revpi0000/data</string>
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>The Revolution Pi will subscribe a topic on which your mqtt client can publish messages with the new io value as payload. <string>RevPi subscribes to an MQTT topic for setting output values. Publish the new I/O value as payload.
Publish values with topic: [basetopic]/set/[outputname]</string> Publish values with topic: [basetopic]/set/[outputname]</string>
</property> </property>
@@ -125,7 +125,7 @@ Publish values with topic: [basetopic]/set/[outputname]</string>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QCheckBox" name="cbx_write_outputs"> <widget class="QCheckBox" name="cbx_write_outputs">
<property name="text"> <property name="text">
<string>Allow MQTT to to set outputs on Revolution Pi</string> <string>Allow MQTT to set outputs on RevPi</string>
</property> </property>
</widget> </widget>
</item> </item>
+3 -3
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Open-Source licenses</string> <string>Open source licenses</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
@@ -87,10 +87,10 @@
</layout> </layout>
<action name="action_start"> <action name="action_start">
<property name="text"> <property name="text">
<string>More licenses...</string> <string>More licenses</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Show more open-source software licenses</string> <string>Show more open source software licenses</string>
</property> </property>
</action> </action>
</widget> </widget>
+5 -5
View File
@@ -210,7 +210,7 @@
</action> </action>
<action name="act_search"> <action name="act_search">
<property name="text"> <property name="text">
<string>&amp;Search Revolution Pi...</string> <string>&amp;Search RevPi...</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+F</string> <string notr="true">Ctrl+F</string>
@@ -223,12 +223,12 @@
</action> </action>
<action name="act_webpage"> <action name="act_webpage">
<property name="text"> <property name="text">
<string>Visit &amp;webpage...</string> <string>Visit &amp;website</string>
</property> </property>
</action> </action>
<action name="act_info"> <action name="act_info">
<property name="text"> <property name="text">
<string>&amp;Info...</string> <string>&amp;Info</string>
</property> </property>
</action> </action>
<action name="act_logs"> <action name="act_logs">
@@ -265,7 +265,7 @@
</action> </action>
<action name="act_pictory"> <action name="act_pictory">
<property name="text"> <property name="text">
<string>piCtory configuraiton...</string> <string>PiCtory configuration</string>
</property> </property>
</action> </action>
<action name="act_disconnect"> <action name="act_disconnect">
@@ -278,7 +278,7 @@
</action> </action>
<action name="act_reset"> <action name="act_reset">
<property name="text"> <property name="text">
<string>Reset driver...</string> <string>Reset driver</string>
</property> </property>
</action> </action>
<action name="act_simulator"> <action name="act_simulator">
+4 -5
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Program information</string> <string>Program Information</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3"> <item row="0" column="0" colspan="3">
@@ -24,7 +24,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>RevPi Python PLC - Commander</string> <string>RevPi Commander (Python/PLC)</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
@@ -114,8 +114,7 @@
</property> </property>
<property name="text"> <property name="text">
<string>RevPiModIO, RevPiPyLoad and RevPiPyControl are community driven projects. They are all free and open source software. <string>RevPiModIO, RevPiPyLoad and RevPiPyControl are community driven projects. They are all free and open source software.
All of them comes with ABSOLUTELY NO WARRANTY, to the extent permitted by All of them come with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.
applicable law.
(c) Sven Sager, License: GPLv2</string> (c) Sven Sager, License: GPLv2</string>
</property> </property>
@@ -140,7 +139,7 @@ applicable law.
<item row="6" column="0" colspan="2"> <item row="6" column="0" colspan="2">
<widget class="QLabel" name="lbl_link"> <widget class="QLabel" name="lbl_link">
<property name="text"> <property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://revpimodio.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://revpimodio.org/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://revpimodio2.readthedocs.io/en/latest/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://revpimodio2.readthedocs.io/en/latest/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="openExternalLinks"> <property name="openExternalLinks">
<bool>true</bool> <bool>true</bool>
+4 -4
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>RevPi Python PLC Logfiles</string> <string>RevPi Python PLC Log Files</string>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
@@ -25,7 +25,7 @@
<item row="1" column="1"> <item row="1" column="1">
<widget class="QCheckBox" name="cbx_wrap"> <widget class="QCheckBox" name="cbx_wrap">
<property name="text"> <property name="text">
<string>Linewrap</string> <string>Line wrap</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -42,7 +42,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="lbl_daemon"> <widget class="QLabel" name="lbl_daemon">
<property name="text"> <property name="text">
<string>RevPiPyLoad - Logfile</string> <string>RevPiPyLoad Log File</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -89,7 +89,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="lbl_app"> <widget class="QLabel" name="lbl_app">
<property name="text"> <property name="text">
<string>Python PLC program - Logfile</string> <string>Python PLC Program Log File</string>
</property> </property>
</widget> </widget>
</item> </item>
+14 -14
View File
@@ -17,20 +17,20 @@
<item> <item>
<widget class="QGroupBox" name="gb_plc"> <widget class="QGroupBox" name="gb_plc">
<property name="title"> <property name="title">
<string>Start / Stop behavior of PLC program</string> <string>PLC Start/Stop Behavior</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="6" column="0"> <item row="6" column="0">
<widget class="QLabel" name="lbl_replace_io"> <widget class="QLabel" name="lbl_replace_io">
<property name="text"> <property name="text">
<string>Replace IO file:</string> <string>Replace I/O file:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1" colspan="2"> <item row="5" column="1" colspan="2">
<widget class="QCheckBox" name="cbx_zeroonerror"> <widget class="QCheckBox" name="cbx_zeroonerror">
<property name="text"> <property name="text">
<string>... after exception and errors</string> <string>after exceptions or errors</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Restart after piCtory changed</string> <string>Restart after PiCtory changes</string>
</property> </property>
</item> </item>
<item> <item>
@@ -70,7 +70,7 @@
<item row="3" column="0" colspan="3"> <item row="3" column="0" colspan="3">
<widget class="QLabel" name="lbl_plc_zero"> <widget class="QLabel" name="lbl_plc_zero">
<property name="text"> <property name="text">
<string>Set process image to NULL if program terminates...</string> <string>Set process image to NULL if the program terminates</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -78,7 +78,7 @@
<widget class="QComboBox" name="cbb_replace_io"> <widget class="QComboBox" name="cbb_replace_io">
<item> <item>
<property name="text"> <property name="text">
<string>Do not use replace io file</string> <string>Do not replace I/O file</string>
</property> </property>
</item> </item>
<item> <item>
@@ -93,7 +93,7 @@
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Give own path and filename</string> <string>Use custom path and file name</string>
</property> </property>
</item> </item>
</widget> </widget>
@@ -101,7 +101,7 @@
<item row="4" column="1" colspan="2"> <item row="4" column="1" colspan="2">
<widget class="QCheckBox" name="cbx_zeroonexit"> <widget class="QCheckBox" name="cbx_zeroonexit">
<property name="text"> <property name="text">
<string>... sucessfully without error</string> <string>without errors</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -135,7 +135,7 @@
<item row="9" column="0" colspan="3"> <item row="9" column="0" colspan="3">
<widget class="QLabel" name="lbl_lbl_reset_driver_action"> <widget class="QLabel" name="lbl_lbl_reset_driver_action">
<property name="text"> <property name="text">
<string>PLC program behavior after piCtory driver reset clicked</string> <string>PLC program behavior after PiCtory driver reset</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -145,7 +145,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_server"> <widget class="QGroupBox" name="gb_server">
<property name="title"> <property name="title">
<string>RevPiPyLoad server services</string> <string>RevPiPyLoad Server Services</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1"> <item row="0" column="1">
@@ -165,7 +165,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QCheckBox" name="cbx_plcserver"> <widget class="QCheckBox" name="cbx_plcserver">
<property name="text"> <property name="text">
<string>Start RevPi piControl server</string> <string>Start piControl server</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -182,7 +182,7 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="lbl_lbl_server_status"> <widget class="QLabel" name="lbl_lbl_server_status">
<property name="text"> <property name="text">
<string>piControl server is:</string> <string>piControl server:</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -202,7 +202,7 @@
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="lbl_lbl_mqtt_status"> <widget class="QLabel" name="lbl_lbl_mqtt_status">
<property name="text"> <property name="text">
<string>MQTT publish service is:</string> <string>MQTT publish service:</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -226,7 +226,7 @@
<item row="4" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="cbx_xmlrpc"> <widget class="QCheckBox" name="cbx_xmlrpc">
<property name="text"> <property name="text">
<string>Activate XML-RPC for RevPiCommander</string> <string>Activate XML-RPC for RevPi Commander</string>
</property> </property>
</widget> </widget>
</item> </item>
+22 -12
View File
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Revolution Pi connections</string> <string>RevPi Connections</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
@@ -37,21 +37,21 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="lbl_address"> <widget class="QLabel" name="lbl_address">
<property name="text"> <property name="text">
<string>Address (DNS/IP):</string> <string>Address (DNS/IP/Socket):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="txt_address"/> <widget class="QLineEdit" name="txt_address"/>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QLabel" name="lbl_port"> <widget class="QLabel" name="lbl_port">
<property name="text"> <property name="text">
<string>Port (Default {0}):</string> <string>Port (default {0}):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QSpinBox" name="sbx_port"> <widget class="QSpinBox" name="sbx_port">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@@ -70,14 +70,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="4" column="0">
<widget class="QLabel" name="lbl_timeout"> <widget class="QLabel" name="lbl_timeout">
<property name="text"> <property name="text">
<string>Connection timeout:</string> <string>Connection timeout:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="4" column="1">
<widget class="QSpinBox" name="sbx_timeout"> <widget class="QSpinBox" name="sbx_timeout">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@@ -86,7 +86,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="suffix"> <property name="suffix">
<string> sec.</string> <string> s</string>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>5</number> <number>5</number>
@@ -96,14 +96,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="5" column="0">
<widget class="QLabel" name="lbl_folder"> <widget class="QLabel" name="lbl_folder">
<property name="text"> <property name="text">
<string>Sub folder:</string> <string>Subfolder:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="5" column="1">
<widget class="QComboBox" name="cbb_folder"> <widget class="QComboBox" name="cbb_folder">
<property name="editable"> <property name="editable">
<bool>true</bool> <bool>true</bool>
@@ -118,6 +118,16 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="lbl_local_socket">
<property name="text">
<string>Use default local socket:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="cbx_local_socket"/>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_ssh"> <widget class="QWidget" name="tab_ssh">
@@ -194,7 +204,7 @@
</property> </property>
<column> <column>
<property name="text"> <property name="text">
<string>Connection name</string> <string>Connection Name</string>
</property> </property>
</column> </column>
<column> <column>
+13 -13
View File
@@ -11,33 +11,33 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>PLC program</string> <string>PLC Program</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QGroupBox" name="gb_plc"> <widget class="QGroupBox" name="gb_plc">
<property name="title"> <property name="title">
<string>PLC program</string> <string>PLC Program</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="lbl_plcarguments"> <widget class="QLabel" name="lbl_plcarguments">
<property name="text"> <property name="text">
<string>Program arguments:</string> <string>Arguments:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="2"> <item row="4" column="0" colspan="2">
<widget class="QLabel" name="lbl_plcprogram_watchdog"> <widget class="QLabel" name="lbl_plcprogram_watchdog">
<property name="text"> <property name="text">
<string>Software watchdog (0=disabled):</string> <string>Software watchdog (0 = disabled):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="3"> <item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="cbx_plcworkdir_set_uid"> <widget class="QCheckBox" name="cbx_plcworkdir_set_uid">
<property name="text"> <property name="text">
<string>Set write permissions for plc program to workdirectory</string> <string>Set write permissions for PLC program working directory</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -57,7 +57,7 @@
<item row="4" column="2"> <item row="4" column="2">
<widget class="QSpinBox" name="sbx_plcprogram_watchdog"> <widget class="QSpinBox" name="sbx_plcprogram_watchdog">
<property name="suffix"> <property name="suffix">
<string> sec.</string> <string> s</string>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>600</number> <number>600</number>
@@ -70,7 +70,7 @@
<item> <item>
<widget class="QGroupBox" name="cb_transfair"> <widget class="QGroupBox" name="cb_transfair">
<property name="title"> <property name="title">
<string>Transfair PLC program</string> <string>Transfer PLC program</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1"> <item row="0" column="1">
@@ -104,21 +104,21 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="lbl_format"> <widget class="QLabel" name="lbl_format">
<property name="text"> <property name="text">
<string>Transfair format:</string> <string>Transfer format:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="cbx_pictory"> <widget class="QCheckBox" name="cbx_pictory">
<property name="text"> <property name="text">
<string>Including piCtory configuration</string> <string>Include PiCtory configuration</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="2"> <item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="cbx_clear"> <widget class="QCheckBox" name="cbx_clear">
<property name="text"> <property name="text">
<string>Remove all files on Revolution Pi before upload</string> <string>Remove all files on RevPi before upload</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -128,7 +128,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_control"> <widget class="QGroupBox" name="gb_control">
<property name="title"> <property name="title">
<string>Control files</string> <string>Control Files</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1"> <item row="1" column="1">
@@ -155,14 +155,14 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="lbl_pictory"> <widget class="QLabel" name="lbl_pictory">
<property name="text"> <property name="text">
<string>piCtory configuraiton</string> <string>PiCtory configuration</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="lbl_procimg"> <widget class="QLabel" name="lbl_procimg">
<property name="text"> <property name="text">
<string>Process image from piControl0</string> <string>Process image from piControl</string>
</property> </property>
</widget> </widget>
</item> </item>
+10 -10
View File
@@ -11,13 +11,13 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>piControl simulator</string> <string>piControl Simulator</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QGroupBox" name="gb_settings"> <widget class="QGroupBox" name="gb_settings">
<property name="title"> <property name="title">
<string>Simulator settings</string> <string>Simulator Settings</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
@@ -30,7 +30,7 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="lbl_configrsc"> <widget class="QLabel" name="lbl_configrsc">
<property name="text"> <property name="text">
<string>piCtory file:</string> <string>PiCtory file:</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -47,7 +47,7 @@
<item row="1" column="2"> <item row="1" column="2">
<widget class="QPushButton" name="btn_configrsc"> <widget class="QPushButton" name="btn_configrsc">
<property name="text"> <property name="text">
<string>select...</string> <string>Select</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -99,7 +99,7 @@
<item row="4" column="1" colspan="2"> <item row="4" column="1" colspan="2">
<widget class="QRadioButton" name="rb_restart_pictory"> <widget class="QRadioButton" name="rb_restart_pictory">
<property name="text"> <property name="text">
<string>Restore piCtory default values</string> <string>Restore PiCtory default values</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
@@ -109,7 +109,7 @@
<item row="5" column="1" colspan="2"> <item row="5" column="1" colspan="2">
<widget class="QRadioButton" name="rb_restart_zero"> <widget class="QRadioButton" name="rb_restart_zero">
<property name="text"> <property name="text">
<string>Reset everything to ZERO</string> <string>Reset all values to NULL</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -119,13 +119,13 @@
<item> <item>
<widget class="QGroupBox" name="gb_info"> <widget class="QGroupBox" name="gb_info">
<property name="title"> <property name="title">
<string>RevPiModIO integration</string> <string>RevPiModIO Integration</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QLabel" name="lbl_info"> <widget class="QLabel" name="lbl_info">
<property name="text"> <property name="text">
<string>You can work with this simulator if you call RevPiModIO with this additional parameters:</string> <string>To use this simulator, call RevPiModIO with the following additional parameters:</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -151,7 +151,7 @@
<item> <item>
<widget class="QPushButton" name="btn_start_pictory"> <widget class="QPushButton" name="btn_start_pictory">
<property name="text"> <property name="text">
<string>Start with piCtory default values</string> <string>Start with PiCtory default values</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+1</string> <string notr="true">Ctrl+1</string>
@@ -171,7 +171,7 @@
<item> <item>
<widget class="QPushButton" name="btn_start_nochange"> <widget class="QPushButton" name="btn_start_nochange">
<property name="text"> <property name="text">
<string>Start without changing actual process image</string> <string>Start without changing the current process image</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+3</string> <string notr="true">Ctrl+3</string>
+4 -4
View File
@@ -26,7 +26,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="lbl_username"> <widget class="QLabel" name="lbl_username">
<property name="text"> <property name="text">
<string>SSH username:</string> <string>SSH user name:</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -53,10 +53,10 @@
<item> <item>
<widget class="QCheckBox" name="cbx_save_password"> <widget class="QCheckBox" name="cbx_save_password">
<property name="toolTip"> <property name="toolTip">
<string>Username and password will be saved in secured operating systems's password storage.</string> <string>Save user name and password in secure password storage.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Save username and password</string> <string>Save user name and password</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -79,7 +79,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Note: The default user for SSH is &quot;pi&quot; which differs from the web configuration. You can find the password on the sticker on the device.</string> <string>Default SSH user is &quot;pi&quot;. The device password is on the RevPi housing sticker.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>