summaryrefslogtreecommitdiffstats
path: root/lib/vehicle-signals
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2023-09-24 12:45:03 -0400
committerScott Murray <scott.murray@konsulko.com>2023-09-24 12:55:47 -0400
commit80a4f8d75a66c22a23e825d4c0fb4065e2e58cb8 (patch)
tree07751588fbd9f0a5cecceabe593a716f01facbac /lib/vehicle-signals
parent9bc83e64c508ad8c69a3950d5421774f9b53a31f (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 dashboard-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 "flutter-" prefix has been dropped from the configuration file name (i.e. it's now just "cluster-dashboard.yaml") to match the naming used for the other Flutter applications. 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 the other applications. - The unused navigation support has been removed to simplify maintenance, as it is more likely that it will be replaced with something else in the future than fixed to be usable. - Removed .dart_tool generated output that had been checked in, and added .gitignore file from flutter-homescreen so that things will hopefully stay clean in the future. Since pubspec.lock is not checked in here, it has also been added to .gitignore. Bug-AGL: SPEC-4762 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: Id35c569cdbb8476a527717ece7b4bb369c4874b7
Diffstat (limited to 'lib/vehicle-signals')
-rw-r--r--lib/vehicle-signals/vehicle_status_provider.dart238
-rw-r--r--lib/vehicle-signals/vss_client.dart113
-rw-r--r--lib/vehicle-signals/vss_path.dart89
-rw-r--r--lib/vehicle-signals/vss_path.dart.hvac60
-rw-r--r--lib/vehicle-signals/vss_provider.dart270
5 files changed, 770 insertions, 0 deletions
diff --git a/lib/vehicle-signals/vehicle_status_provider.dart b/lib/vehicle-signals/vehicle_status_provider.dart
new file mode 100644
index 0000000..9518f59
--- /dev/null
+++ b/lib/vehicle-signals/vehicle_status_provider.dart
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: Apache-2.0
+
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+class VehicleStatus {
+ VehicleStatus({
+ required this.speed,
+ required this.rpm,
+ required this.fuelLevel,
+ required this.coolantTemp,
+ required this.isLeftIndicator,
+ required this.isRightIndicator,
+ required this.selectedGear,
+ required this.isLowBeam,
+ required this.isHighBeam,
+ required this.isHazardLightOn,
+ required this.travelledDistance,
+ required this.isParkingOn,
+ required this.performanceMode,
+ required this.ambientAirTemp,
+ required this.cruiseControlSpeed,
+ required this.isCruiseControlActive,
+ required this.isCruiseControlError,
+ required this.isMILon,
+ required this.isTrunkLocked,
+ required this.isTrunkOpen,
+ required this.isBatteryCharging,
+
+ // steering switches
+ required this.vehicleDistanceUnit,
+ required this.isSteeringCruiseEnable,
+ required this.isSteeringCruiseSet,
+ required this.isSteeringCruiseResume,
+ required this.isSteeringCruiseCancel,
+ required this.isSteeringLaneWarning,
+ required this.isSteeringInfo,
+ });
+
+ final double speed;
+ final double rpm;
+ final double fuelLevel;
+ final double coolantTemp;
+ final double cruiseControlSpeed;
+ final bool isLeftIndicator;
+ final bool isRightIndicator;
+ final String selectedGear;
+ final String performanceMode;
+ final double ambientAirTemp;
+ final bool isLowBeam;
+ final bool isHighBeam;
+ final bool isParkingOn;
+ final bool isHazardLightOn;
+ final bool isTrunkOpen;
+ final bool isTrunkLocked;
+ final bool isMILon;
+ final bool isCruiseControlActive;
+ final bool isCruiseControlError;
+ final bool isBatteryCharging;
+ final double travelledDistance;
+
+ final String vehicleDistanceUnit;
+ final bool isSteeringCruiseEnable;
+ final bool isSteeringCruiseSet;
+ final bool isSteeringCruiseResume;
+ final bool isSteeringCruiseCancel;
+ final bool isSteeringLaneWarning;
+ final bool isSteeringInfo;
+
+ VehicleStatus copyWith({
+ double? speed,
+ double? rpm,
+ double? fuelLevel,
+ double? coolantTemp,
+ bool? isLeftIndicator,
+ bool? isRightIndicator,
+ String? selectedGear,
+ String? performanceMode,
+ double? ambientAirTemp,
+ bool? isLowBeam,
+ bool? isHighBeam,
+ bool? isHazardLightOn,
+ bool? isParkingOn,
+ bool? isTrunkLocked,
+ bool? isTrunkOpen,
+ bool? isMILon,
+ bool? isCruiseControlError,
+ bool? isCruiseControlActive,
+ bool? isBatteryCharging,
+ double? travelledDistance,
+ double? cruiseControlSpeed,
+ // Steering
+ String? vehicleDistanceUnit,
+ bool? isSteeringCruiseEnable,
+ bool? isSteeringCruiseSet,
+ bool? isSteeringCruiseResume,
+ bool? isSteeringCruiseCancel,
+ bool? isSteeringLaneWarning,
+ bool? isSteeringInfo,
+ }) {
+ return VehicleStatus(
+ speed: speed ?? (this.speed),
+ rpm: rpm ?? this.rpm,
+ fuelLevel: fuelLevel ?? this.fuelLevel,
+ coolantTemp: coolantTemp ?? this.coolantTemp,
+ isLeftIndicator: isLeftIndicator ?? this.isLeftIndicator,
+ isRightIndicator: isRightIndicator ?? this.isRightIndicator,
+ selectedGear: selectedGear ?? this.selectedGear,
+ isLowBeam: isLowBeam ?? this.isLowBeam,
+ isHighBeam: isHighBeam ?? this.isHighBeam,
+ isHazardLightOn: isHazardLightOn ?? this.isHazardLightOn,
+ travelledDistance: travelledDistance ?? this.travelledDistance,
+ isParkingOn: isParkingOn ?? this.isParkingOn,
+ performanceMode: performanceMode ?? this.performanceMode,
+ isTrunkLocked: isTrunkLocked ?? this.isTrunkLocked,
+ isTrunkOpen: isTrunkOpen ?? this.isTrunkOpen,
+ ambientAirTemp: ambientAirTemp ?? this.ambientAirTemp,
+ isMILon: isMILon ?? this.isMILon,
+ isCruiseControlActive:
+ isCruiseControlActive ?? this.isCruiseControlActive,
+ cruiseControlSpeed: cruiseControlSpeed ?? this.cruiseControlSpeed,
+ isCruiseControlError: isCruiseControlError ?? this.isCruiseControlError,
+ isBatteryCharging: isBatteryCharging ?? this.isBatteryCharging,
+ isSteeringCruiseEnable:
+ isSteeringCruiseEnable ?? this.isSteeringCruiseEnable,
+ isSteeringCruiseSet: isSteeringCruiseSet ?? this.isSteeringCruiseSet,
+ isSteeringCruiseResume:
+ isSteeringCruiseResume ?? this.isSteeringCruiseResume,
+ isSteeringCruiseCancel:
+ isSteeringCruiseCancel ?? this.isSteeringCruiseCancel,
+ isSteeringInfo: isSteeringInfo ?? this.isSteeringInfo,
+ isSteeringLaneWarning:
+ isSteeringLaneWarning ?? this.isSteeringLaneWarning,
+ vehicleDistanceUnit: vehicleDistanceUnit ?? this.vehicleDistanceUnit,
+ );
+ }
+}
+
+final vehicleStatusProvider =
+ StateNotifierProvider<VehicleStatusNotifier, VehicleStatus>(
+ (ref) => VehicleStatusNotifier(),
+);
+
+class VehicleStatusNotifier extends StateNotifier<VehicleStatus> {
+ VehicleStatusNotifier() : super(_initialValue);
+ static final VehicleStatus _initialValue = VehicleStatus(
+ speed: 140,
+ rpm: 7000,
+ fuelLevel: 90,
+ coolantTemp: 90,
+ isLeftIndicator: false,
+ isRightIndicator: false,
+ selectedGear: "P",
+ performanceMode: "normal",
+ isHazardLightOn: false,
+ isHighBeam: true,
+ isLowBeam: false,
+ isParkingOn: true,
+ travelledDistance: 888,
+ ambientAirTemp: 25,
+ cruiseControlSpeed: 60,
+ isCruiseControlActive: false,
+ isCruiseControlError: false,
+ isMILon: false,
+ isTrunkLocked: true,
+ isTrunkOpen: false,
+ isBatteryCharging: true,
+ isSteeringCruiseEnable: false,
+ isSteeringCruiseSet: false,
+ isSteeringCruiseResume: false,
+ isSteeringCruiseCancel: false,
+ isSteeringInfo: false,
+ isSteeringLaneWarning: false,
+ vehicleDistanceUnit: 'km',
+ );
+ void update({
+ double? speed,
+ double? rpm,
+ double? fuelLevel,
+ double? coolantTemp,
+ bool? isLeftIndicator,
+ bool? isRightIndicator,
+ String? selectedGear,
+ String? performanceMode,
+ double? ambientAirTemp,
+ bool? isLowBeam,
+ bool? isHighBeam,
+ bool? isHazardLightOn,
+ bool? isMILon,
+ bool? isParkingOn,
+ bool? isTrunkOpen,
+ bool? isTrunkLocked,
+ bool? isCruiseControlActive,
+ bool? isCruiseControlError,
+ bool? isBatteryCharging,
+ double? travelledDistance,
+ double? cruiseControlSpeed,
+ //
+ String? vehicleDistanceUnit,
+ bool? isSteeringCruiseEnable,
+ bool? isSteeringCruiseSet,
+ bool? isSteeringCruiseResume,
+ bool? isSteeringCruiseCancel,
+ bool? isSteeringLaneWarning,
+ bool? isSteeringInfo,
+ }) {
+ state = state.copyWith(
+ speed: speed,
+ rpm: rpm,
+ fuelLevel: fuelLevel,
+ coolantTemp: coolantTemp,
+ isLeftIndicator: isLeftIndicator,
+ isRightIndicator: isRightIndicator,
+ selectedGear: selectedGear,
+ isLowBeam: isLowBeam,
+ isHighBeam: isHighBeam,
+ isHazardLightOn: isHazardLightOn,
+ travelledDistance: travelledDistance,
+ performanceMode: performanceMode,
+ isParkingOn: isParkingOn,
+ isTrunkOpen: isTrunkOpen,
+ isTrunkLocked: isTrunkLocked,
+ isMILon: isMILon,
+ ambientAirTemp: ambientAirTemp,
+ isCruiseControlActive: isCruiseControlActive,
+ isCruiseControlError: isCruiseControlError,
+ cruiseControlSpeed: cruiseControlSpeed,
+ isBatteryCharging: isBatteryCharging,
+ //
+ isSteeringCruiseEnable: isSteeringCruiseEnable,
+ isSteeringCruiseSet: isSteeringCruiseSet,
+ isSteeringCruiseResume: isSteeringCruiseResume,
+ isSteeringCruiseCancel: isSteeringCruiseCancel,
+ isSteeringInfo: isSteeringInfo,
+ isSteeringLaneWarning: isSteeringLaneWarning,
+ vehicleDistanceUnit: vehicleDistanceUnit,
+ );
+ }
+}
diff --git a/lib/vehicle-signals/vss_client.dart b/lib/vehicle-signals/vss_client.dart
new file mode 100644
index 0000000..e416d87
--- /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_cluster_dashboard/generated/kuksa/val/v1/val.pbgrpc.dart';
+import 'package:flutter_cluster_dashboard/generated/kuksa/val/v1/types.pb.dart';
+import 'package:flutter_cluster_dashboard/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));
+ }
+
+}
diff --git a/lib/vehicle-signals/vss_path.dart b/lib/vehicle-signals/vss_path.dart
new file mode 100644
index 0000000..78538b9
--- /dev/null
+++ b/lib/vehicle-signals/vss_path.dart
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: Apache-2.0
+
+class VSSPath {
+ static const String vehicleSpeed = "Vehicle.Speed";
+
+ static const String vehicleEngineRPM =
+ "Vehicle.Powertrain.CombustionEngine.Speed";
+
+ static const String vehicleFuelLevel = "Vehicle.Powertrain.FuelSystem.Level";
+
+ static const String vehicleCoolantTemp =
+ "Vehicle.Powertrain.CombustionEngine.ECT";
+
+ static const String vehicleAmbientAirTemperature =
+ "Vehicle.Exterior.AirTemperature";
+
+ static const String vehicleLeftIndicator =
+ "Vehicle.Body.Lights.DirectionIndicator.Left.IsSignaling";
+
+ static const String vehicleRightIndicator =
+ "Vehicle.Body.Lights.DirectionIndicator.Right.IsSignaling";
+
+ //Selected Gear output=> 0=Neutral, 1/2/..=Forward, -1/..=Reverse, 126=Park, 127=Drive
+ static const String vehicleSelectedGear =
+ "Vehicle.Powertrain.Transmission.SelectedGear";
+
+ static const String vehicleLowBeamOn = "Vehicle.Body.Lights.Beam.Low.IsOn";
+
+ static const String vehicleHighBeamOn = "Vehicle.Body.Lights.Beam.High.IsOn";
+
+ static const String vehicleParkingLightOn = "Vehicle.Body.Lights.Parking.IsOn";
+
+ static const String vehicleHazardLightOn = "Vehicle.Body.Lights.Hazard.IsSignaling";
+
+ static const String vehicleTravelledDistance = "Vehicle.TravelledDistance";
+
+ static const String vehicleTrunkLocked = "Vehicle.Body.Trunk.Rear.IsLocked";
+
+ static const String vehicleTrunkOpen = "Vehicle.Body.Trunk.Rear.IsOpen";
+
+ // \"normal\",\"sport\",\"economy\",\"snow\",\"rain\"]
+ static const String vehiclePerformanceMode =
+ "Vehicle.Powertrain.Transmission.PerformanceMode";
+
+ static const String vehicleMIL = "Vehicle.OBD.Status.IsMILOn";
+
+ static const String vehicleCruiseControlError =
+ "Vehicle.ADAS.CruiseControl.IsError";
+
+ static const String vehicleCruiseControlSpeedSet =
+ "Vehicle.ADAS.CruiseControl.SpeedSet";
+
+ static const String vehicleCruiseControlActive =
+ "Vehicle.ADAS.CruiseControl.IsActive";
+
+ static const String vehicleBatteryChargingStatus =
+ "Vehicle.Powertrain.TractionBattery.Charging.IsCharging";
+
+ static const String steeringCruiseEnable =
+ "Vehicle.Cabin.SteeringWheel.Switches.CruiseEnable";
+
+ static const String steeringCruiseSet =
+ "Vehicle.Cabin.SteeringWheel.Switches.CruiseSet";
+
+ static const String steeringCruiseResume =
+ "Vehicle.Cabin.SteeringWheel.Switches.CruiseResume";
+
+ static const String steeringCruiseCancel =
+ "Vehicle.Cabin.SteeringWheel.Switches.CruiseCancel";
+
+ static const String steeringLaneDepWarn =
+ "Vehicle.Cabin.SteeringWheel.Switches.LaneDepartureWarning";
+
+ static const String steeringInfo =
+ "Vehicle.Cabin.SteeringWheel.Switches.Info";
+
+ static const String vehicleDistanceUnit =
+ "Vehicle.Cabin.Infotainment.HMI.DistanceUnit";
+
+ static const String vehicleCurrLat = "Vehicle.CurrentLocation.Latitude";
+
+ static const String vehicleCurrLon = "Vehicle.CurrentLocation.Longitude";
+
+ static const String vehicleDestLat =
+ "Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Latitude";
+
+ static const String vehicleDestLon =
+ "Vehicle.Cabin.Infotainment.Navigation.DestinationSet.Longitude";
+}
diff --git a/lib/vehicle-signals/vss_path.dart.hvac b/lib/vehicle-signals/vss_path.dart.hvac
new file mode 100644
index 0000000..df90a48
--- /dev/null
+++ b/lib/vehicle-signals/vss_path.dart.hvac
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: Apache-2.0
+
+
+class VSSPath {
+
+ static const String vehicleOutsideTemperature =
+ "Vehicle.AmbientAirTemperature";
+
+ static const String vehicleInsideTemperature =
+ "Vehicle.Cabin.HVAC.AmbientAirTemperature";
+
+ static const String vehicleIsAirConditioningActive =
+ "Vehicle.Cabin.HVAC.IsAirConditioningActive";
+
+ static const String vehicleIsFrontDefrosterActive =
+ "Vehicle.Cabin.HVAC.IsFrontDefrosterActive";
+
+ static const String vehicleIsRearDefrosterActive =
+ "Vehicle.Cabin.HVAC.IsRearDefrosterActive";
+
+ static const String vehicleIsRecirculationActive =
+ "Vehicle.Cabin.HVAC.IsRecirculationActive";
+
+ static const String vehicleFrontLeftAirDistribution =
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.AirDistribution";
+
+ static const String vehicleFrontLeftFanSpeed =
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.FanSpeed";
+
+ static const String vehicleFrontLeftTemp =
+ "Vehicle.Cabin.HVAC.Station.Row1.Left.Temperature";
+
+ static const String vehicleFrontRightAirDistribution =
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.AirDistribution";
+
+ static const String vehicleFrontRightFanSpeed =
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.FanSpeed";
+
+ static const String vehicleFrontRightTemp =
+ "Vehicle.Cabin.HVAC.Station.Row1.Right.Temperature";
+
+ static const String vehicleRearLeftAirDistribution =
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.AirDistribution";
+
+ static const String vehicleRearLeftFanSpeed =
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.FanSpeed";
+
+ static const String vehicleRearLeftTemp =
+ "Vehicle.Cabin.HVAC.Station.Row2.Left.Temperature";
+
+ static const String vehicleRearRightAirDistribution =
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.AirDistribution";
+
+ static const String vehicleRearRightFanSpeed =
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.FanSpeed";
+
+ static const String vehicleRearRightTemp =
+ "Vehicle.Cabin.HVAC.Station.Row2.Right.Temperature";
+
+}
diff --git a/lib/vehicle-signals/vss_provider.dart b/lib/vehicle-signals/vss_provider.dart
new file mode 100644
index 0000000..7820a52
--- /dev/null
+++ b/lib/vehicle-signals/vss_provider.dart
@@ -0,0 +1,270 @@
+// 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_cluster_dashboard/generated/kuksa/val/v1/val.pbgrpc.dart';
+import 'package:flutter_cluster_dashboard/generated/kuksa/val/v1/types.pb.dart';
+import 'package:flutter_cluster_dashboard/config.dart';
+import 'package:flutter_cluster_dashboard/vehicle-signals/vss_client.dart';
+import 'package:flutter_cluster_dashboard/vehicle-signals/vss_path.dart';
+import 'package:flutter_cluster_dashboard/vehicle-signals/vehicle_status_provider.dart';
+
+class DashboardVssClient extends VssClient {
+ @override
+ final List<String> signals = [
+ VSSPath.vehicleSpeed,
+ VSSPath.vehicleEngineRPM,
+ VSSPath.vehicleFuelLevel,
+ VSSPath.vehicleCoolantTemp,
+ VSSPath.vehicleAmbientAirTemperature,
+ VSSPath.vehicleLeftIndicator,
+ VSSPath.vehicleRightIndicator,
+ VSSPath.vehicleHazardLightOn,
+ VSSPath.vehicleHighBeamOn,
+ VSSPath.vehicleLowBeamOn,
+ VSSPath.vehicleSelectedGear,
+ VSSPath.vehiclePerformanceMode,
+ VSSPath.vehicleParkingLightOn,
+ VSSPath.vehicleTrunkLocked,
+ VSSPath.vehicleTrunkOpen,
+ VSSPath.vehicleMIL,
+ VSSPath.vehicleCruiseControlError,
+ VSSPath.vehicleCruiseControlSpeedSet,
+ VSSPath.vehicleCruiseControlActive,
+ VSSPath.vehicleBatteryChargingStatus,
+ VSSPath.vehicleDistanceUnit,
+ VSSPath.steeringCruiseEnable,
+ VSSPath.steeringCruiseSet,
+ VSSPath.steeringCruiseResume,
+ VSSPath.steeringCruiseCancel,
+ VSSPath.steeringInfo,
+ VSSPath.steeringLaneDepWarn
+ ];
+
+ DashboardVssClient({required super.config, required super.channel, required super.stub, required super.ref});
+
+ static String? numToGear(int? number) {
+ switch (number) {
+ case -1:
+ return 'R';
+ case 0:
+ return 'N';
+ case 126:
+ return 'P';
+ case 127:
+ return 'D';
+ default:
+ return null;
+ }
+ }
+
+ @override
+ void handleSignalUpdates(EntryUpdate update) {
+ var vehicleStatus = ref.read(vehicleStatusProvider.notifier);
+ switch (update.entry.path) {
+ case VSSPath.vehicleSpeed:
+ if (update.entry.value.hasFloat()) {
+ vehicleStatus.update(speed: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleEngineRPM:
+ if (update.entry.value.hasFloat()) {
+ vehicleStatus.update(rpm: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleFuelLevel:
+ if (update.entry.value.hasUint32()) {
+ vehicleStatus.update(fuelLevel: update.entry.value.uint32.toDouble());
+ }
+ break;
+ case VSSPath.vehicleCoolantTemp:
+ if (update.entry.value.hasFloat()) {
+ vehicleStatus.update(coolantTemp: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleAmbientAirTemperature:
+ if (update.entry.value.hasFloat()) {
+ vehicleStatus.update(ambientAirTemp: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleLeftIndicator:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isLeftIndicator: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleRightIndicator:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isRightIndicator: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleHighBeamOn:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12) {
+ vehicleStatus.update(isHighBeam: true);
+ vehicleStatus.update(isLowBeam: false);
+ } else {
+ vehicleStatus.update(isHighBeam: false);
+ }
+ }
+ break;
+ case VSSPath.vehicleParkingLightOn:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isParkingOn: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleLowBeamOn:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12) {
+ vehicleStatus.update(isHighBeam: false);
+ vehicleStatus.update(isLowBeam: true);
+ } else {
+ vehicleStatus.update(isLowBeam: false);
+ }
+ }
+ break;
+ case VSSPath.vehicleHazardLightOn:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isHazardLightOn: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleSelectedGear:
+ if (update.entry.value.hasInt32()) {
+ vehicleStatus.update(
+ selectedGear: numToGear(update.entry.value.int32));
+ }
+ break;
+ case VSSPath.vehiclePerformanceMode:
+ if (update.entry.value.hasString()) {
+ vehicleStatus.update(performanceMode: update.entry.value.string);
+ }
+ break;
+ case VSSPath.vehicleTravelledDistance:
+ if (update.entry.value.hasFloat()) {
+ vehicleStatus.update(travelledDistance: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleTrunkLocked:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isTrunkLocked: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleTrunkOpen:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isTrunkOpen: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleMIL:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isMILon: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleCruiseControlError:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isCruiseControlError: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleCruiseControlSpeedSet:
+ if (update.entry.value.hasFloat()) {
+ vehicleStatus.update(cruiseControlSpeed: update.entry.value.float);
+ }
+ break;
+ case VSSPath.vehicleCruiseControlActive:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isCruiseControlActive: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleBatteryChargingStatus:
+ if (update.entry.value.hasBool_12()) {
+ vehicleStatus.update(isBatteryCharging: update.entry.value.bool_12);
+ }
+ break;
+ case VSSPath.vehicleDistanceUnit:
+ if (update.entry.value.hasString()) {
+ vehicleStatus.update(vehicleDistanceUnit: update.entry.value.string);
+ }
+ break;
+
+ // Steering wheel switches
+ case VSSPath.steeringCruiseEnable:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12) {
+ if (vehicleStatus.state.isSteeringCruiseEnable) {
+ vehicleStatus.update(isSteeringCruiseEnable: false);
+ vehicleStatus.update(isSteeringCruiseSet: false);
+ } else {
+ vehicleStatus.update(isSteeringCruiseEnable: true);
+ }
+ }
+ }
+ break;
+ case VSSPath.steeringCruiseSet:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12 &&
+ vehicleStatus.state.isSteeringCruiseEnable) {
+ vehicleStatus.update(isSteeringCruiseSet: true);
+ }
+ }
+ break;
+ case VSSPath.steeringCruiseResume:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12 &&
+ vehicleStatus.state.isSteeringCruiseEnable) {
+ vehicleStatus.update(isSteeringCruiseSet: true);
+ }
+ }
+ break;
+ case VSSPath.steeringCruiseCancel:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12) {
+ vehicleStatus.update(isSteeringCruiseSet: false);
+ }
+ }
+ break;
+ case VSSPath.steeringInfo:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12) {
+ vehicleStatus.update(
+ isSteeringInfo: !vehicleStatus.state.isSteeringInfo);
+ }
+ }
+ break;
+ case VSSPath.steeringLaneDepWarn:
+ if (update.entry.value.hasBool_12()) {
+ if (update.entry.value.bool_12) {
+ vehicleStatus.update(
+ isSteeringLaneWarning:
+ !(vehicleStatus.state.isSteeringLaneWarning));
+ }
+ }
+ break;
+
+ default:
+ print("ERROR: Unexpected path ${update.entry.path}");
+ break;
+ }
+ }
+}
+
+final vssClientProvider = Provider((ref) {
+ var config = ref.read(kuksaConfigProvider);
+ debugPrint("Using ${config.hostname}:${config.port}");
+ ChannelCredentials creds;
+ if (config.use_tls && config.ca_certificate.isNotEmpty) {
+ print("Using TLS");
+ if (config.tls_server_name.isNotEmpty)
+ creds = ChannelCredentials.secure(certificates: config.ca_certificate, authority: config.tls_server_name);
+ else
+ creds = ChannelCredentials.secure(certificates: config.ca_certificate);
+ } else {
+ creds = ChannelCredentials.insecure();
+ }
+ final channel = ClientChannel(config.hostname,
+ port: config.port,
+ options: ChannelOptions(credentials: creds));
+
+ final stub = VALClient(channel);
+
+ return DashboardVssClient(config: config, channel: channel, stub: stub, ref: ref);
+});