EUCData.kt
package io.github.tritbool.euc.ble.models
/**
* Represents real-time telemetry data from an Electric Unicycle.
*
* Contains all decoded data fields from BLE characteristic notifications,
* including speed, voltage, current, temperature, battery information, and
* various device-specific settings and status flags.
*
* @param frameType Internal identifier for the frame format
* @param speed Current speed in km/h
* @param voltage Battery voltage in volts
* @param current Current draw in amps (positive = discharge, negative = charge)
* @param temperature Temperature in degrees Celsius
* @param batteryLevel Battery level percentage (0-100)
* @param distance Current trip distance in kilometers
* @param power Current power consumption in watts
* @param pwm PWM duty cycle percentage (0-100), null if unavailable
* @param timestamp Timestamp in milliseconds
* @param rawData Raw byte data from the BLE characteristic
* @param manufacturer Manufacturer name
* @param model Device model name
* @param serialNumber Device serial number, null if unavailable
* @param firmwareVersion Firmware version, null if unavailable
* @param isCharging Current charging status
* @param rideTime Total ride time in seconds
* @param cellVoltages Individual cell voltages, null if unavailable
* @param motorTemperature Motor temperature in degrees Celsius, null if unavailable
* @param totalDistance Total distance traveled in kilometers, null if unavailable
* @param pedalsMode Pedals mode value (legacy-mapped, typically 0..2)
* @param alarmMode Encoded alarm mode value (firmware-dependent, usually 0..3)
* @param rollAngleMode Encoded roll-angle mode value (firmware-dependent, usually 0..3)
* @param usesMiles Whether the device uses miles instead of km/h
* @param autoPowerOffMinutes Auto power-off time in minutes, null if unavailable
* @param tiltBackSpeed Tilt-back speed threshold, null if unavailable
* @param ledMode LED mode setting, null if unavailable
* @param lightMode Light mode setting, null if unavailable
* @param alertFlags Alert flags bitmap, null if unavailable
* @param wheelAlarm Wheel alarm status, null if unavailable
* @param topSpeed Session top speed in km/h, null if unavailable
* @param fanStatus Fan on/off status, null if unavailable
* @param chargingStatus Charging status byte, null if unavailable
* @param temperature2 Secondary temperature (e.g., motor/board), null if unavailable
* @param cpuLoad CPU load percentage, null if unavailable
* @param speedLimit Configured speed limit in km/h, null if unavailable
* @param alarm1Speed Alarm 1 speed threshold, null if unavailable
* @param alarm2Speed Alarm 2 speed threshold, null if unavailable
* @param alarm3Speed Alarm 3 speed threshold, null if unavailable
* @param wheelMaxSpeed Maximum speed setting, null if unavailable
* @param wheelDistance Trip distance reported by wheel, null if unavailable
* @param angle Pitch/tilt angle in degrees, null if unavailable
* @param phaseCurrent Motor phase current in amps, null if unavailable
* @param roll Roll angle in degrees, null if unavailable
* @param torque Estimated torque in Nm, null if unavailable
* @param mode Ride mode string (e.g. "active", "idle", "charging"), null if unavailable
*/
data class EUCData(
internal val frameType: String = "BASE",
val speed: Double, // km/h
val voltage: Double, // volts
val current: Double, // amps
val temperature: Double, // degrees Celsius
val batteryLevel: Int, // percentage 0-100
val distance: Double, // kilometers
val power: Double, // watts
val pwm: Double? = null, // PWM duty cycle percentage (0-100), null if unavailable
val timestamp: Long, // milliseconds
val rawData: ByteArray, // raw byte data
val manufacturer: String, // manufacturer name
val model: String, // device model
val serialNumber: String? = null, // device serial
val firmwareVersion: String? = null, // firmware version
val isCharging: Boolean, // charging status
val rideTime: Long, // ride time in seconds
val cellVoltages: List<Double>? = null, // individual cell voltages
val motorTemperature: Double? = null, // motor temperature in degrees Celsius (null if not available)
val totalDistance: Double? = null,
val pedalsMode: Int? = null, // mode value exposed by protocol (legacy-mapped, typically 0..2)
val alarmMode: Int? = null, // encoded alarm mode value (firmware-dependent, usually 0..3)
val rollAngleMode: Int? = null, // encoded roll-angle mode value (firmware-dependent, usually 0..3)
val usesMiles: Boolean? = null,
val autoPowerOffMinutes: Int? = null,
val tiltBackSpeed: Int? = null,
val ledMode: Int? = null,
val lightMode: Int? = null,
val alertFlags: Int? = null,
val wheelAlarm: Boolean? = null,
val topSpeed: Double? = null, // session top speed in km/h
val fanStatus: Int? = null, // fan on/off status
val chargingStatus: Int? = null, // charging status byte
val temperature2: Double? = null, // secondary temperature (e.g. motor/board)
val cpuLoad: Int? = null, // CPU load percentage
val speedLimit: Double? = null, // configured speed limit in km/h
val alarm1Speed: Int? = null, // alarm 1 speed threshold
val alarm2Speed: Int? = null, // alarm 2 speed threshold
val alarm3Speed: Int? = null, // alarm 3 speed threshold
val wheelMaxSpeed: Int? = null, // max speed setting
val wheelDistance: Double? = null, // trip distance (wheel-reported)
val angle: Double? = null, // pitch/tilt angle in degrees (null if unavailable)
val phaseCurrent: Double? = null, // Phase current in amps (motor-side), null if unavailable
val roll: Double? = null, // Roll angle in degrees, null if unavailable
val torque: Double? = null, // Torque estimate (Nm), null if unavailable
val mode: String? = null // Ride mode/state string (e.g. "active", "idle"), null if unavailable
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as EUCData
if (timestamp != other.timestamp) return false
if (manufacturer != other.manufacturer) return false
if (model != other.model) return false
return true
}
override fun hashCode(): Int {
var result = timestamp.hashCode()
result = 31 * result + manufacturer.hashCode()
result = 31 * result + model.hashCode()
return result
}
}