summaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
authorsuchinton2001 <suchinton.2001@gmail.com>2023-10-15 23:30:36 +0530
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2023-10-19 16:19:32 +0000
commit20fe2d131df0041e121eccaf4fc58d4ac88dfbbc (patch)
treed555cd863e644014e9eb7a3fb9b759de246b6c2e /extras
parente875973f63fc9a9582e957eb7264a4a589b78a97 (diff)
agl-demo-control-panel: Refactor Settings, Config and UI scaling
V1: - Add template to specify new configs in config.ini - Add drop-down to load all configurations specified in config.ini - Add new assets and refine UI elements (Scaling issue fixed) - Add size grip to main window - Add options in settings to configure port and AGL's CA.pem file - Removed unused or redundant files V2: - Check for user configs agl-demo-control-panel.ini & config.ini before resorting to default config.ini - Check for CA.pem and jwt tokens in default paths - Add new fields in settings for CA.pem file, jwt token path, TLS Server name - Fix crash in dashboard.py module due to icon.availableSizes() V3: Add Start/Stop states for the client V4: Block subscription event updates to the UI when values are changed on the control panel Bug-AGL: SPEC-4905 Signed-off-by: suchinton2001 <suchinton.2001@gmail.com> Change-Id: Id7883ba3bc88248dabb58d54e6e931f6d365fd54
Diffstat (limited to 'extras')
-rw-r--r--extras/FeedKuksa.py42
-rw-r--r--extras/Kuksa_Instance.py35
-rw-r--r--extras/UI_Handeler.py19
-rw-r--r--extras/config.ini48
-rw-r--r--extras/config.py99
5 files changed, 182 insertions, 61 deletions
diff --git a/extras/FeedKuksa.py b/extras/FeedKuksa.py
index 56e902e..cda2a30 100644
--- a/extras/FeedKuksa.py
+++ b/extras/FeedKuksa.py
@@ -14,12 +14,15 @@
limitations under the License.
"""
-import time
import logging
from PyQt5.QtCore import QThread
+from PyQt5.QtCore import pyqtSignal
from . import Kuksa_Instance as kuksa_instance
+import threading
class FeedKuksa(QThread):
+ sending_values = pyqtSignal()
+ finished_sending_values = pyqtSignal()
"""
A class to handle sending values to Kuksa.
@@ -85,20 +88,25 @@ class FeedKuksa(QThread):
Exception
If there is an error sending values to Kuksa.
"""
- if self.client is not None:
- if self.client.checkConnection():
- try:
- if attribute is not None:
- self.client.setValue(path, str(value), attribute)
- else:
- self.client.setValue(path, str(value))
- except Exception as e:
- logging.error(f"Error sending values to kuksa {e}")
- self.set_instance()
- else:
- logging.error("Kuksa client is not connected, try reconnecting")
- self.set_instance()
- else:
+
+ if self.client is None:
logging.error("Kuksa client is None, try reconnecting")
- time.sleep(2)
- self.set_instance() \ No newline at end of file
+ return
+
+ if not self.client.checkConnection():
+ logging.error("Kuksa client is not connected, try reconnecting")
+ threading.Thread(target=self.set_instance).start()
+ return
+
+ try:
+ if attribute is not None:
+ self.sending_values.emit()
+ self.client.setValue(path, value, attribute)
+ else:
+ self.sending_values.emit()
+ self.client.setValue(path, value)
+
+ self.finished_sending_values.emit()
+ except Exception as e:
+ logging.error(f"Error sending values to kuksa {e}")
+ threading.Thread(target=self.set_instance).start() \ No newline at end of file
diff --git a/extras/Kuksa_Instance.py b/extras/Kuksa_Instance.py
index 500e039..1ff8056 100644
--- a/extras/Kuksa_Instance.py
+++ b/extras/Kuksa_Instance.py
@@ -19,8 +19,6 @@ import kuksa_client as kuksa
import threading
import time
-from extras import config
-
class KuksaClientSingleton:
"""
A singleton class that provides a single instance of KuksaClientThread.
@@ -73,28 +71,11 @@ class KuksaClientSingleton:
if KuksaClientSingleton._instance is not None:
raise Exception("This class is a singleton!")
- self.kuksa_config = config.KUKSA_CONFIG
- self.ws_token = config.WS_TOKEN
- self.grpc_token = config.GRPC_TOKEN
-
- if self.kuksa_config["protocol"] == 'ws':
- self.token = self.ws_token
- if self.kuksa_config["protocol"] == 'grpc':
- self.token = self.grpc_token
-
- try:
- self.client = kuksa.KuksaClientThread(self.kuksa_config)
- self.client.authorize(self.token)
- self.client.start()
- time.sleep(2)
- if not self.client.checkConnection():
- self.client = None
- except Exception as e:
- print(e)
+ self.client = None
KuksaClientSingleton._instance = self
- def reconnect(self, config):
+ def reconnect(self, config, token):
"""
Reconnects the client with the given configuration and token.
@@ -107,18 +88,10 @@ class KuksaClientSingleton:
"""
if self.client:
self.client.stop()
-
- if self.kuksa_config["protocol"] == 'ws':
- self.token = self.ws_token
- self.kuksa_config["port"] = "8090"
- if self.kuksa_config["protocol"] == 'grpc':
- self.token = self.grpc_token
- self.kuksa_config["port"] = "55555"
- self.client = kuksa.KuksaClientThread(self.kuksa_config)
- self.client.authorize(self.token)
+ self.client = kuksa.KuksaClientThread(config)
+ self.client.authorize(token)
self.client.start()
- return self.client
def get_client(self):
"""
diff --git a/extras/UI_Handeler.py b/extras/UI_Handeler.py
index 2bfcfc4..261df94 100644
--- a/extras/UI_Handeler.py
+++ b/extras/UI_Handeler.py
@@ -24,16 +24,30 @@ from PyQt5.QtWidgets import QDesktopWidget
import logging
import json
+from . import FeedKuksa as feed_kuksa
from . import Kuksa_Instance as kuksa_instance
# Global variables
subscribed = False
should_execute_callback = True
+block_subscription_updates = False
class UI_Handeler(MainWindow):
"""
This class handles the UI of the AGL Demo Control Panel application.
"""
+ def __init__(self):
+ self.feed_kuksa = feed_kuksa.FeedKuksa()
+ self.feed_kuksa.sending_values.connect(self.block_updates)
+ self.feed_kuksa.finished_sending_values.connect(self.unblock_updates)
+
+ def block_updates(self):
+ global block_subscription_updates
+ block_subscription_updates = True
+
+ def unblock_updates(self):
+ global block_subscription_updates
+ block_subscription_updates = False
def Hide_Navbar(self, bool_arg):
"""
@@ -143,9 +157,10 @@ class UI_Handeler(MainWindow):
Args:
- data: The data received from the signal.
"""
- global should_execute_callback
- if should_execute_callback is False:
+ global block_subscription_updates
+ if block_subscription_updates:
return
+
IC_Page = self.stackedWidget.widget(1)
HVAC_Page = self.stackedWidget.widget(2)
diff --git a/extras/config.ini b/extras/config.ini
new file mode 100644
index 0000000..0f64a4f
--- /dev/null
+++ b/extras/config.ini
@@ -0,0 +1,48 @@
+[default]
+preferred-config=AGL-kuksa-val-server
+
+# [cutom-config-template]
+# ip=<ip address>
+# port=<port number>
+# protocol=<ws|grpc> # ws/grpc -> kuksa-val-server, grpc -> databroker
+# insecure=<true|false> # Note: Use insecure mode only if server is also running in insecure mode
+# cacert=<default|/path/to/CA.pem>
+# token=<default|/path/to/token>
+# tls_server_name=<name>
+
+[kuksa-val-server]
+ip=localhost
+port=8090
+protocol=ws
+insecure=false
+token=default
+tls_server_name=
+
+
+[databroker]
+ip=localhost
+port=55555
+protocol=grpc
+insecure=false
+token=default
+tls_server_name=Server
+
+
+[AGL-kuksa-val-server]
+ip=localhost
+port=8090
+protocol=ws
+insecure=false
+cacert=default
+token=default
+tls_server_name=
+
+
+[AGL-databroker]
+ip=10.42.0.95
+port=55555
+protocol=grpc
+insecure=false
+cacert=default
+token=default
+tls_server_name=Server
diff --git a/extras/config.py b/extras/config.py
index 3309b71..2b92342 100644
--- a/extras/config.py
+++ b/extras/config.py
@@ -16,19 +16,96 @@
import os
import platform
+from configparser import ConfigParser
python_version = f"python{'.'.join(platform.python_version_tuple()[:2])}"
-CA = os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/cert/CA.pem"))
+def check_paths(*paths):
+ return {path: os.path.exists(path) for path in paths}
-KUKSA_CONFIG = {
- "ip": '127.0.0.1',
- "port": "55555",
- 'protocol': 'grpc',
- 'insecure': False,
- 'cacertificate': CA,
- 'tls_server_name': "Server",
-}
+CONFIG_PATHS = check_paths(
+ "/etc/agl-demo-control-panel.ini",
+ os.path.join(os.path.expanduser("~"), ".local/share/agl-demo-control-panel/config.ini"),
+ os.path.abspath(os.path.join(os.path.dirname(__file__), 'config.ini'))
+)
-WS_TOKEN = os.path.join(os.path.expanduser("~"), f".local/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token")
-GRPC_TOKEN = os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/token/grpc/actuate-provide-all.token"))
+CA_PATHS = check_paths(
+ "/etc/kuksa-val/CA.pem",
+ f"/usr/lib/{python_version}/site-packages/kuksa_certificates/CA.pem",
+ os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/cert/CA.pem"))
+)
+
+WS_TOKEN_PATHS = check_paths(
+ f"/usr/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token",
+ os.path.join(os.path.expanduser("~"), f".local/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token")
+)
+
+GRPC_TOKEN_PATHS = check_paths(
+ f"/usr/lib/{python_version}/site-packages/kuksa_certificates/jwt/super-admin.json.token",
+ os.path.abspath(os.path.join(os.path.dirname(__file__), "../assets/token/grpc/actuate-provide-all.token"))
+)
+
+config = ConfigParser()
+config_path = next((path for path, exists in CONFIG_PATHS.items() if exists), None)
+if config_path:
+ config.read(config_path)
+
+CA_PATH = next((path for path, exists in CA_PATHS.items() if exists), None)
+WS_TOKEN = next((path for path, exists in WS_TOKEN_PATHS.items() if exists), None)
+GRPC_TOKEN = next((path for path, exists in GRPC_TOKEN_PATHS.items() if exists), None)
+
+KUKSA_CONFIG = {}
+KUKSA_TOKEN = None
+
+def select_config(preferred_config):
+ """
+ Selects a configuration from the config.ini file based on the preferred_config parameter.
+
+ Args:
+ preferred_config (str): The name of the configuration section to select.
+
+ Returns:
+ Tuple[str, Dict[str, Union[str, bool]], str]: A tuple containing the name of the selected configuration section,
+ a dictionary containing the configuration options for the selected section, and the token to use for the selected
+ protocol.
+ """
+ global KUKSA_CONFIG, KUKSA_TOKEN
+ KUKSA_CONFIG.clear()
+
+ if config.has_section(preferred_config):
+ KUKSA_CONFIG['ip'] = config[preferred_config]['ip']
+ KUKSA_CONFIG['port'] = config[preferred_config]['port']
+ KUKSA_CONFIG['protocol'] = config[preferred_config]['protocol']
+ KUKSA_CONFIG['insecure'] = False if config[preferred_config]['insecure'] == 'false' else True
+
+ if config.has_option(preferred_config, 'cacert'):
+ KUKSA_CONFIG['cacertificate'] = config[preferred_config]['cacert'] if os.path.exists(config[preferred_config]['cacert']) else CA_PATH
+ else:
+ KUKSA_CONFIG['cacertificate'] = None
+
+ KUKSA_CONFIG['tls_server_name'] = config[preferred_config]['tls_server_name']
+
+ if config.has_option(preferred_config, 'token'):
+ if config[preferred_config]['token'] == 'default':
+ KUKSA_TOKEN = get_default_token(KUKSA_CONFIG['protocol'])
+ elif os.path.exists(config[preferred_config]['token']):
+ KUKSA_TOKEN = config[preferred_config]['token']
+ else:
+ ValueError(f"Token file {config[preferred_config]['token']} not found")
+ else:
+ raise ValueError(f"Config section {preferred_config} not found in config.ini")
+
+ return preferred_config, KUKSA_CONFIG , KUKSA_TOKEN
+
+def get_list_configs():
+ return config.sections()[1:]
+
+def get_default_config():
+ defaultConfigName = config.get('default', 'preferred-config')
+ return defaultConfigName
+
+def get_default_token(protocol):
+ if protocol == 'grpc':
+ return GRPC_TOKEN
+ else:
+ return WS_TOKEN \ No newline at end of file