kuksa-vss-init: rework into agl-vss-helper
[AGL/meta-agl-demo.git] / recipes-demo / agl-vss-helper / files / agl-vss-helper.py
diff --git a/recipes-demo/agl-vss-helper/files/agl-vss-helper.py b/recipes-demo/agl-vss-helper/files/agl-vss-helper.py
new file mode 100644 (file)
index 0000000..73ac6b9
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 Aakash Solanki, tech2aks@gmail.com
+# Copyright (c) 2024 Scott Murray <scott.murray@konsulko.com>
+#
+# SPDX-License-Identifier: MIT
+
+import sys
+from pathlib import Path
+import yaml
+import asyncio
+import concurrent.futures
+from kuksa_client.grpc.aio import VSSClient
+from kuksa_client.grpc import Datapoint
+from systemd.daemon import notify
+
+# Defaults
+hostname = "localhost"
+port = 55555
+config_filename = "/etc/xdg/AGL/agl-vss-helper.yaml"
+token_filename = "/etc/xdg/AGL/agl-vss-helper/agl-vss-helper.token"
+ca_cert_filename = "/etc/kuksa-val/CA.pem"
+tls_server_name = "localhost"
+verbose = False
+
+async def main():
+    client = VSSClient(hostname,
+                       port,
+                       root_certificates=Path(ca_cert_filename),
+                       tls_server_name=tls_server_name,
+                       token=token,
+                       ensure_startup_connection=True)
+    await client.connect()
+    print(f"Connected to KUKSA.val databroker at {hostname}:{port}")
+    if "initialize" in config and isinstance(config["initialize"], list):
+        for entry in config["initialize"]:
+            if "signal" in entry and "value" in entry:
+                if verbose:
+                    print(f"Setting {entry['signal']} to {entry['value']}")
+                await client.set_current_values({ entry["signal"] : Datapoint(entry["value"]) })
+
+    notify("READY=1")
+
+    if "mock" in config and isinstance(config["mock"], list):
+        if len(config["mock"]) != 0:
+            print(f"Mocking actuators:")
+            for signal in config["mock"]:
+                print(f"  {signal}")
+            async for updates in client.subscribe_target_values(config["mock"]):
+                for signal in updates:
+                    if updates[signal] is not None:
+                        if verbose:
+                            print(f"Actuating {signal} to {updates[signal].value}")
+                        await client.set_current_values({ signal : Datapoint(updates[signal].value) })
+
+
+#
+# Initialization
+#
+
+try:
+    config_file = open(config_filename, "r")
+    config = yaml.safe_load(config_file)
+except yaml.YAMLError as exc:
+    print(f"Could not parse configuration: ${exc}")
+except:
+    print(f"Could not read configuration")
+
+if "verbose" in config and isinstance(config["verbose"], bool):
+    verbose = config["verbose"]
+if "hostname" in config and isinstance(config["hostname"], string):
+    hostname = config["hostname"]
+if "port" in config and isinstance(config["port"], int):
+    port = config["port"]
+if "use-tls" in config and isinstance(config["use-tls"], bool):
+    use_tls = config["use-tls"]
+if "token-file" in config and isinstance(config["token-file"], string):
+    token_filename = config["token-file"]
+if "ca-certificate" in config and isinstance(config["ca-certificate"], string):
+    ca_cert_filename = config["ca-certificate"]
+
+if token_filename != "":
+    if verbose:
+        print(f"Reading authorization token {token_filename}")
+    token_file = open(token_filename, "r")
+    token = token_file.read()
+else:
+    token = ""
+
+print("Starting")
+try:
+    asyncio.run(main())
+except KeyboardInterrupt:
+    print("Exiting")
+
+notify("STOPPING=1")
+sys.exit(0)