diff options
author | Scott Murray <scott.murray@konsulko.com> | 2023-09-20 12:26:45 -0400 |
---|---|---|
committer | Scott Murray <scott.murray@konsulko.com> | 2023-09-20 12:48:19 -0400 |
commit | 6a853805d2479bf7b111511b1f94907e425c607a (patch) | |
tree | 343a651a5e4a944de525f585eceb752d9ed3840a /lib/vehicle-signals/vss_client.dart | |
parent | 20d76f947ef9d4a9093df0e5ad04476963655173 (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 hvac-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 "hvac.yaml" instead
of "hvac_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.
- Bumped minimum SDK version to 2.18 in pubspec.yaml to enable
"super" keyword support. This matches what the version was set
to in flutter-homescreen.
- The Vehicle and VehicleSignals classes have been reworked into
a VehicleAcStatus class + provider, and users have been updated
to use the Riverpod provider select functionality to attempt to
reduce naive over-updating.
- VSS paths have been rationalized to use the definitions in the
VSSPath class so only one location will need to be updated on any
signal name changes.
- Added .gitignore file from flutter-homescreen to keep things
clean in the future.
Bug-AGL: SPEC-4762
Signed-off-by: Scott Murray <scott.murray@konsulko.com>
Change-Id: Idbabb54ead52bf38796f264a3c8a270aa170e2cd
Diffstat (limited to 'lib/vehicle-signals/vss_client.dart')
-rw-r--r-- | lib/vehicle-signals/vss_client.dart | 113 |
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..b9769e1 --- /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_hvac/generated/kuksa/val/v1/val.pbgrpc.dart'; +import 'package:flutter_hvac/generated/kuksa/val/v1/types.pb.dart'; +import 'package:flutter_hvac/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)); + } + +} |