diff options
author | suchinton2001 <suchinton.2001@gmail.com> | 2023-10-15 23:30:36 +0530 |
---|---|---|
committer | Jan-Simon Moeller <jsmoeller@linuxfoundation.org> | 2023-10-19 16:19:32 +0000 |
commit | 20fe2d131df0041e121eccaf4fc58d4ac88dfbbc (patch) | |
tree | d555cd863e644014e9eb7a3fb9b759de246b6c2e /extras | |
parent | e875973f63fc9a9582e957eb7264a4a589b78a97 (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.py | 42 | ||||
-rw-r--r-- | extras/Kuksa_Instance.py | 35 | ||||
-rw-r--r-- | extras/UI_Handeler.py | 19 | ||||
-rw-r--r-- | extras/config.ini | 48 | ||||
-rw-r--r-- | extras/config.py | 99 |
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 |