aboutsummaryrefslogtreecommitdiffstats
path: root/lib/vehicle-signals/vss_client.dart
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2023-09-14 14:01:24 -0400
committerScott Murray <scott.murray@konsulko.com>2023-09-14 14:37:02 -0400
commitcbbb9f40e283d12f6c52ad28609516f390316f7a (patch)
treed8d2cd8f4641299dd35a3138c0e28f11443928d6 /lib/vehicle-signals/vss_client.dart
parent5ce59ba69f1451ec18c565b7b18301856553f574 (diff)
Rework to use KUKSA.val databroker gRPC API
Rework to move from the WebSocket API with the older KUKSA.val server to the gRPC "VAL" API of the databroker. Changes include: - All VISS WebSocket API code has been removed, and the signal providers replumbed to be driven by a new VssClient class with a homescreen-specific child class to hold all the gRPC API handling. - The generated code for the VAL API and its dependencies has been checked in under lib/generated, as there still does not seem to be a good way to generate it during the Flutter build. - The configuration file is now expected to be "homescreen.yaml" instead of "homescreen_config.yaml". The authorization token field name has been renamed to "authorization", and there are new "use-tls" and "ca-certificate" configuration fields. TLS is disabled by default for now, and the default CA certificate is /etc/kuksa.val/CA.pem. - Updated .gitignore to cover a couple of generated files that weren't included. Bug-AGL: SPEC-4762, SPEC-4903 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: I1b95ed27a72435364d54ec846f2be88e3d8bb092
Diffstat (limited to 'lib/vehicle-signals/vss_client.dart')
-rw-r--r--lib/vehicle-signals/vss_client.dart113
1 files changed, 113 insertions, 0 deletions
diff --git a/lib/vehicle-signals/vss_client.dart b/lib/vehicle-signals/vss_client.dart
new file mode 100644
index 0000000..d733c92
--- /dev/null
+++ b/lib/vehicle-signals/vss_client.dart
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: Apache-2.0
+import 'dart:io';
+import 'package:meta/meta.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:grpc/grpc.dart';
+import 'package:flutter_homescreen/generated/kuksa/val/v1/val.pbgrpc.dart';
+import 'package:flutter_homescreen/generated/kuksa/val/v1/types.pb.dart';
+import 'package:flutter_homescreen/config.dart';
+
+abstract class VssClient {
+ final KuksaConfig config;
+ final ClientChannel channel;
+ final VALClient stub;
+ final Ref ref;
+
+ // Extenders will likely override this
+ final List<String> signals = [];
+
+ VssClient({required this.config, required this.channel, required this.stub, required this.ref});
+
+ // Abstract method extenders must implement
+ void handleSignalUpdates(EntryUpdate update);
+
+ void run() async {
+ if (signals.isEmpty)
+ return;
+
+ var request = SubscribeRequest();
+ for (var i = 0; i < signals.length; i++) {
+ var entry = SubscribeEntry();
+ entry.path = signals[i];
+ entry.fields.add(Field.FIELD_PATH);
+ entry.fields.add(Field.FIELD_VALUE);
+ request.entries.add(entry);
+ }
+
+ try {
+ Map<String, String> metadata = {};
+ if (config.authorization.isNotEmpty) {
+ metadata = {'authorization': "Bearer ${config.authorization}" };
+ }
+ var responseStream = stub.subscribe(request, options: CallOptions(metadata: metadata));
+ await for (var response in responseStream) {
+ for (var update in response.updates) {
+ if (!(update.hasEntry() && update.entry.hasPath()))
+ continue;
+ handleSignalUpdates(update);
+ }
+ }
+ } catch (e) {
+ print(e);
+ }
+ }
+
+ void setUint32(String path, int value, [bool actuator = true]) async {
+ var dp = Datapoint()
+ ..uint32 = value;
+ set(path, dp, actuator);
+ }
+
+ void setInt32(String path, int value, [bool actuator = true]) async {
+ var dp = Datapoint()
+ ..int32 = value;
+ set(path, dp, actuator);
+ }
+
+ void setBool(String path, bool value, [bool actuator = true]) async {
+ var dp = Datapoint()
+ ..bool_12 = value;
+ set(path, dp, actuator);
+ }
+
+ void setString(String path, String value, [bool actuator = true]) async {
+ var dp = Datapoint()
+ ..string = value;
+ set(path, dp, actuator);
+ }
+
+ void setFloat(String path, double value, [bool actuator = true]) async {
+ var dp = Datapoint()
+ ..float = value;
+ set(path, dp, actuator);
+ }
+
+ void setDouble(String path, double value, [bool actuator = true]) async {
+ var dp = Datapoint()
+ ..double_18 = value;
+ set(path, dp, actuator);
+ }
+
+ void set(String path, Datapoint dp, bool actuator) async {
+ var entry = DataEntry()
+ ..path = path;
+ var update = EntryUpdate();
+ if (actuator) {
+ entry.actuatorTarget = dp;
+ update.fields.add(Field.FIELD_ACTUATOR_TARGET);
+ } else {
+ entry.value = dp;
+ update.fields.add(Field.FIELD_VALUE);
+ }
+ update.entry = entry;
+ var request = SetRequest();
+ request.updates.add(update);
+ Map<String, String> metadata = {};
+ if (config.authorization.isNotEmpty) {
+ metadata = {'authorization': "Bearer ${config.authorization}" };
+ }
+ await stub.set(request, options: CallOptions(metadata: metadata));
+ }
+
+}