use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NexusCommand {
pub id: Uuid,
pub command: InternalCommand,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum InternalCommand {
SetMode(RobotMode), GoTo {
target: GeoPose, },
VelocityCmd {
linear_mps: f32,
angular_rps: f32,
},
Stop, Resume, InvokeService {
service_name: String,
setting: Option<bool>,
},
SetMissionRunStatus {
mission_id: String,
run_id: String,
status: MissionStatus,
},
MissionCommand(MissionCommand),
Feature(FeatureOp),
SpatialDirective(SpatialDirectiveOp),
Object(ObjectOp),
SettingUpdate(Vec<SettingUpdate>),
DeleteMission {
mission_id: String,
},
TeleopJoy(TeleopJoy),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum UplinkMsg {
MissionRunStatus(MissionRunStatus),
MotionTelemetry(MotionTelemetry),
StatusTelemetry(StatusTelemetry),
TelemetryExtras(TelemetryExtras),
EventTelemetry(EventTelemetry), UiCapabilities(UiCapabilities), Fault(Fault), Shape(ReportedShapeOp), Object(ObjectOp),
SystemHealth(SystemHealth),
UsageTelemetry(UsageTelemetry),
ConsumableStatus(ConsumableStatus), CurrentSettings(Vec<SettingUpdate>), Message(Message), AgentInfo(AgentInfo), SpatialDirectiveStatus(SpatialDirectiveStatus), }
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum MessageLevel {
Info,
Warn,
Error,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Message {
pub unix_time_ms: i64,
pub level: MessageLevel,
pub message: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentInfo {
pub agent_version: String,
pub software_version: Option<String>,
pub os_info: Option<String>, pub uptime_s: Option<u64>, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TeleopJoy {
pub source_id: String, pub session_id: String, pub axes: Vec<f32>,
pub buttons: Vec<bool>,
pub timestamp_ms: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum FeatureOp {
Upsert(SpatialFeature),
Delete { id: String },
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum SpatialDirectiveOp {
Upsert(SpatialDirective),
Delete { id: String },
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ObjectOp {
Upsert(Object),
Delete { id: String },
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ReportedShapeOp {
Upsert(ReportedShape),
Delete { id: String },
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RobotState {
pub motion_dirty: bool,
pub status_dirty: bool,
pub extras_dirty: bool,
pub motion_telemetry: MotionTelemetry,
pub status_telemetry: StatusTelemetry,
pub extras: TelemetryExtras,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum FaultSeverity {
Info,
Minor,
Major,
Critical,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Fault {
pub unix_time_ms: i64,
pub fault_id: String, pub source: String, pub severity: FaultSeverity,
pub active: bool, pub category: String, pub description: String, pub suggested_action: String, }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum MissionStatus {
Unknown,
Ready,
Starting, Running,
Paused,
Blocked,
Aborted,
Completed,
Error,
}
impl MissionStatus {
pub fn is_terminal(self) -> bool {
matches!(
self,
MissionStatus::Completed | MissionStatus::Aborted | MissionStatus::Error
)
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SensorReading {
pub key: String,
pub value: Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub unix_time_ms: Option<i64>, }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum DisplayHint {
None, OnOff, Gauge, Text,
Online, WarningLight, Temperature, Progress, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Range {
pub min: f64,
pub max: f64,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SensorDescriptor {
pub key: String, pub label: String, pub value_type: ValueType, #[serde(skip_serializing_if = "Option::is_none")]
pub unit: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
pub range: Option<Range>, pub display_hint: DisplayHint, }
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TelemetryExtras {
pub unix_time_ms: i64,
pub kv: Vec<SensorReading>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SettingUpdate {
pub key: String,
pub value: Value,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SettingDescriptor {
pub key: String,
pub label: String,
pub value_type: ValueType,
pub default: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub range: Option<Range>,
#[serde(skip_serializing_if = "Option::is_none")]
pub step: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Role {
Viewer,
Operator,
Admin,
Owner,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum CapabilityType {
Trigger, SetBool, MissionType, }
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum DangerLevel {
#[default]
Normal, Warning, Critical, }
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ServiceCapability {
pub name: String, pub description: String, pub capability_type: CapabilityType, pub confirmation_message: Option<String>, pub state_key: Option<String>, pub requires_role: Role, #[serde(default)]
pub danger_level: DangerLevel, }
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiCapabilities {
pub services: Vec<ServiceCapability>, pub sensors: Vec<SensorDescriptor>, pub settings: Vec<SettingDescriptor>, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum ValueType {
String, Int, Number, Bool, Enum { options: Vec<String> }, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase", tag = "type", content = "data")]
pub enum Value {
String(String),
Int(i32),
Number(f64),
Bool(bool),
Enum(String),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum RobotMode {
Manual,
Auto,
Teleop,
Idle,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MissionRunStatus {
pub unix_time_ms: i64,
pub mission_id: String,
pub run_id: String,
pub status: MissionStatus,
pub status_message: Option<String>,
pub progress_x100: Option<u16>, pub current_path_id: Option<String>,
pub current_target: Option<GeoPose>,
pub current_step: Option<u32>, pub total_steps: Option<u32>,
pub time_started_ms: Option<i64>,
pub expected_end_time_ms: Option<i64>,
pub time_completed_ms: Option<i64>,
pub name: Option<String>, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct AssetIdentity {
pub id: String, pub name: String, pub rev: u32, pub hash: String, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum SpatialFeature {
Shape(Shape),
Route(Route),
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum CapabilityTiming {
ImmediateTrigger, AtTargetTrigger, DuringStep, DuringFeature, FinalTrigger, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MissionCapability {
pub name: String,
pub timing: CapabilityTiming,
pub value: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MissionCommand {
pub mission_id: String, pub run_id: String, pub name: String, pub user_id: String, pub detail: String, pub scheduled_start_ms: i64, pub expected_end_time_ms: Option<i64>, pub mission_parameters: Vec<SettingUpdate>, pub capabilities: Vec<MissionCapability>, pub feature: Option<SpatialFeature>, }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SpatialDirective {
pub directive_id: String, pub name: String, pub start_time_ms: i64, pub expire_time_ms: Option<i64>, pub zone_parameters: Vec<SettingUpdate>,
pub capabilities: Vec<String>, pub spatial: SpatialFeature,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SpatialDirectiveStatus {
pub directive_id: String,
pub last_eval_time_ms: i64,
pub active: bool, pub inside_zone: bool, pub distance_to_zone_m: Option<f32>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Schedule {
pub owner: TriggerSource,
pub timezone: String,
pub start_time_ms: Option<i64>,
pub end_time_ms: Option<i64>,
pub kind: ScheduleKind,
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum TriggerSource {
Server,
Agent,
Robot,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase", rename_all_fields = "camelCase")]
pub enum ScheduleKind {
Cron {
expr: String,
},
Interval {
every_seconds: u32,
},
Once, }
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EventTelemetry {
pub unix_time_ms: i64,
pub kind: EventKind,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum EventKind {
EstopEngaged,
EstopReleased,
ModeChanged {
from: RobotMode,
to: RobotMode,
}, MissionStarted {
mission_id: String,
}, MissionCompleted {
mission_id: String,
}, FaultRaised {
fault_code: String,
description: String,
}, FaultCleared {
fault_code: String, },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub enum GpsSource {
#[default]
Real, Simulated, Estimated, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MotionTelemetry {
pub unix_time_ms: i64,
pub pose: Option<GeoPose>,
pub velocity: Option<VelTwist>,
pub gps_fix: Option<GpsFixType>, pub gps_source: GpsSource,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StatusTelemetry {
pub unix_time_ms: i64,
pub battery: Option<BatteryStatus>,
pub fuel: Option<FuelStatus>,
pub range_remaining_m: Option<f64>, pub runtime_remaining_s: Option<f64>, pub mode: Option<RobotMode>,
pub estop: EStop,
pub faulted: bool,
pub accepting_missions: bool, pub status: String, }
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UsageTelemetry {
pub unix_time_ms: i64,
pub total_distance_m: f64,
pub auto_distance_m: f64,
pub manual_distance_m: f64,
pub uptime_total_s: f64,
pub drive_time_total_s: f64,
pub auto_time_total_s: f64,
pub mission_count_total: u32,
pub charge_cycles_total: u32,
pub reboot_count: u32,
pub last_reboot_unix_time_ms: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SystemHealth {
pub unix_time_ms: i64,
pub device_id: String, pub cpu_pct: f32,
pub mem_pct: f32,
pub disk_pct: f32,
pub cpu_temp: f32,
pub signal_strength: f32, pub signal_quality: f32, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EStop {
pub unix_time_ms: i64,
pub active: bool,
pub ids: Vec<String>,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ScopeType {
Robot = 0,
Fleet = 1,
World = 2,
User = 3,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ObjectType {
Unknown = 0,
Person = 1,
Animal = 2,
Vehicle = 3,
Robot = 4,
Structure = 5,
Equipment = 6,
Obstacle = 7,
Debris = 8,
Hazard = 9,
Marker = 10,
PointOfInterest = 11,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ReportedLayerRole {
Coverage = 0, Occupied = 1, Reserved = 2, Consumed = 3, Hazard = 4, Blocked = 5, PlannedPath = 6, }
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum LayerRole {
AllowedArea = 0, Preferred = 1, Keepout = 2, SoftExclusion = 3, WorkArea = 4, Target = 5, Queue = 6, ControlZone = 7, TriggerZone = 8, Coverage = 10, Occupied = 11, Reserved = 12, Consumed = 13, Hazard = 14, Blocked = 15, PlannedPath = 16, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ShapeData {
Point(GeoPoint2),
MultiPoint(Vec<GeoPoint2>),
LineString(Vec<GeoPoint2>),
MultiLineString(Vec<Vec<GeoPoint2>>),
Polygon {
exterior: Vec<GeoPoint2>,
holes: Vec<Vec<GeoPoint2>>,
},
MultiPolygon(Vec<PolygonData>),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PolygonData {
pub exterior: Vec<GeoPoint2>,
pub holes: Vec<Vec<GeoPoint2>>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Shape {
pub identity: AssetIdentity,
pub data: ShapeData,
pub area_type: LayerRole,
pub scope: ScopeType,
pub min_z_m: f64,
pub max_z_m: f64,
pub level_id: i32, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReportedShape {
pub identity: AssetIdentity,
pub data: ShapeData,
pub area_type: ReportedLayerRole,
pub scope: ScopeType,
pub expire_time_ms: i64,
pub min_z_m: f64,
pub max_z_m: f64,
pub level_id: i32, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum RouteData {
Waypoint(GeoPose),
MultiWaypoint(Vec<GeoPose>),
Path(Vec<GeoPose>),
MultiPath(Vec<Vec<GeoPose>>),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Route {
pub identity: AssetIdentity,
pub data: RouteData,
pub area_type: LayerRole,
pub scope: ScopeType,
pub feature_type: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Trajectory {
pub speed_mps: f64, pub course_deg: f64, pub vertical_rate_mps: f64, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GeoPoint2 {
pub lon: f64,
pub lat: f64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Object {
pub id: String,
pub name: String,
pub unix_time_ms: i64,
pub expires_unix_time_ms: i64,
pub scope: ScopeType, pub object_type: ObjectType,
pub location: GeoPose,
pub trajectory: Trajectory, pub radius_m: f64, }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum GpsFixType {
Unknown,
Invalid,
#[serde(rename = "GPS")]
GPS, #[serde(rename = "DGPS")]
DGPS, #[serde(rename = "SBAS")]
SBAS,
FloatRTK,
FixedRTK,
#[serde(rename = "PPS")]
PPS,
GBAS, }
impl GpsFixType {
pub fn from_ros_status(value: i8) -> Self {
match value {
-1 => Self::Invalid,
0 => Self::GPS,
1 => Self::SBAS,
2 => Self::FixedRTK,
_ => Self::Unknown,
}
}
pub fn from_u8(value: u8) -> Self {
match value {
0 => Self::Unknown,
1 => Self::Invalid,
2 => Self::GPS,
3 => Self::DGPS,
4 => Self::SBAS,
5 => Self::FloatRTK,
6 => Self::FixedRTK,
7 => Self::PPS,
_ => Self::Unknown,
}
}
pub fn to_u8(self) -> u8 {
match self {
Self::Unknown => 0,
Self::Invalid => 1,
Self::GPS => 2,
Self::DGPS => 3,
Self::SBAS => 4,
Self::FloatRTK => 5,
Self::FixedRTK => 6,
Self::PPS => 7,
Self::GBAS => 6,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct GeoPose {
pub lon_deg: f64, pub lat_deg: f64, pub altitude_m: f64, pub heading_deg: f64, }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VelTwist {
pub linear_mps: f32,
pub angular_rps: f32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum PowerSupplyStatus {
Unknown,
Charging,
Discharging,
NotCharging,
Full,
}
impl PowerSupplyStatus {
pub fn from_u8(value: u8) -> Self {
match value {
1 => Self::Charging,
2 => Self::Discharging,
3 => Self::NotCharging,
4 => Self::Full,
_ => Self::Unknown,
}
}
pub fn to_u8(self) -> u8 {
match self {
Self::Unknown => 0,
Self::Charging => 1,
Self::Discharging => 2,
Self::NotCharging => 3,
Self::Full => 4,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum PowerSupplyHealth {
Unknown,
Good,
Overheat,
Dead,
Overvoltage,
UnspecifiedFailure,
Cold,
WatchdogTimerExpire,
SafetyTimerExpire,
}
impl PowerSupplyHealth {
pub fn from_u8(value: u8) -> Self {
match value {
1 => Self::Good,
2 => Self::Overheat,
3 => Self::Dead,
4 => Self::Overvoltage,
5 => Self::UnspecifiedFailure,
6 => Self::Cold,
7 => Self::WatchdogTimerExpire,
8 => Self::SafetyTimerExpire,
_ => Self::Unknown,
}
}
pub fn to_u8(self) -> u8 {
match self {
Self::Unknown => 0,
Self::Good => 1,
Self::Overheat => 2,
Self::Dead => 3,
Self::Overvoltage => 4,
Self::UnspecifiedFailure => 5,
Self::Cold => 6,
Self::WatchdogTimerExpire => 7,
Self::SafetyTimerExpire => 8,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum PowerSupplyTechnology {
Unknown,
NiMH,
LiIon,
LiPo,
LiFe,
NiCd,
LiMn,
}
impl PowerSupplyTechnology {
pub fn from_u8(value: u8) -> Self {
match value {
1 => Self::NiMH,
2 => Self::LiIon,
3 => Self::LiPo,
4 => Self::LiFe,
5 => Self::NiCd,
6 => Self::LiMn,
_ => Self::Unknown,
}
}
pub fn to_u8(self) -> u8 {
match self {
Self::Unknown => 0,
Self::NiMH => 1,
Self::LiIon => 2,
Self::LiPo => 3,
Self::LiFe => 4,
Self::NiCd => 5,
Self::LiMn => 6,
}
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BatteryStatus {
pub soc_pct: f32, pub voltage_v: Option<f32>,
pub current_a: Option<f32>,
pub charge_ah: Option<f32>,
pub capacity_ah: Option<f32>,
pub design_capacity_ah: Option<f32>,
pub temperature: Option<f32>,
pub power_supply_status: PowerSupplyStatus,
pub power_supply_health: PowerSupplyHealth,
pub power_supply_technology: PowerSupplyTechnology,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FuelStatus {
pub level_pct: f32, pub volume_remaining: Option<f32>,
pub capacity: Option<f32>, pub volume_unit: Option<String>, pub efficiency: Option<f32>, pub efficiency_unit: Option<String>, pub is_refueling: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ConsumableStatus {
pub unix_time_ms: i64,
pub kind: String, pub tank_id: String, pub level_pct: f32, pub amount_remaining: f32, pub unit: String, pub is_critical: bool, }