Use device class enum where possible and supply possible states for those sensors (#4394)

* Use device class enum where possible and supply possible states for those sensors

* Add some missing sensors

* Review comments and suppress lint

* Add media session sensor to enum device class
This commit is contained in:
Daniel Shokouhi 2024-05-13 12:41:18 -07:00 committed by GitHub
parent 67d6be2d01
commit d640b9d974
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 137 additions and 67 deletions

View File

@ -40,7 +40,8 @@ class ActivitySensorManager : BroadcastReceiver(), SensorManager {
"sensor",
commonR.string.basic_sensor_name_activity,
commonR.string.sensor_description_detected_activity,
"mdi:walk"
"mdi:walk",
deviceClass = "enum"
)
private val sleepConfidence = SensorManager.BasicSensor(
@ -111,7 +112,9 @@ class ActivitySensorManager : BroadcastReceiver(), SensorManager {
activity,
probActivity,
getSensorIcon(probActivity),
result.probableActivities.associate { typeToString(it) to it.confidence }
result.probableActivities.associate { typeToString(it) to it.confidence }.plus(
"options" to listOf("in_vehicle", "on_bicycle", "on_foot", "still", "tilting", "walking", "running")
)
)
}
}

View File

@ -119,6 +119,7 @@ class CarSensorManager :
R.string.basic_sensor_name_car_fuel_type,
R.string.sensor_description_car_fuel_type,
"mdi:gas-station",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
),
autoPermissions = listOf("com.google.android.gms.permission.CAR_FUEL"),
@ -131,6 +132,7 @@ class CarSensorManager :
R.string.basic_sensor_name_car_ev_connector_type,
R.string.sensor_description_car_ev_connector_type,
"mdi:car-electric",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
),
autoPermissions = listOf("com.google.android.gms.permission.CAR_FUEL"),
@ -182,6 +184,38 @@ class CarSensorManager :
private fun connected(): Boolean = HaCarAppService.carInfo != null
private val fuelTypeMap = mapOf(
EnergyProfile.FUEL_TYPE_BIODIESEL to "Biodiesel",
EnergyProfile.FUEL_TYPE_CNG to "Compressed natural gas",
EnergyProfile.FUEL_TYPE_DIESEL_1 to "#1 Grade Diesel",
EnergyProfile.FUEL_TYPE_DIESEL_2 to "#2 Grade Diesel",
EnergyProfile.FUEL_TYPE_E85 to "85% ethanol/gasoline blend",
EnergyProfile.FUEL_TYPE_ELECTRIC to "Electric",
EnergyProfile.FUEL_TYPE_HYDROGEN to "Hydrogen fuel cell",
EnergyProfile.FUEL_TYPE_LEADED to "Leaded gasoline",
EnergyProfile.FUEL_TYPE_LNG to "Liquified natural gas",
EnergyProfile.FUEL_TYPE_LPG to "Liquified petroleum gas",
EnergyProfile.FUEL_TYPE_OTHER to "Other",
EnergyProfile.FUEL_TYPE_UNLEADED to "Unleaded gasoline",
EnergyProfile.FUEL_TYPE_UNKNOWN to STATE_UNKNOWN
)
private val evTypeMap = mapOf(
EnergyProfile.EVCONNECTOR_TYPE_CHADEMO to "CHAdeMo fast charger connector",
EnergyProfile.EVCONNECTOR_TYPE_COMBO_1 to "Combined Charging System Combo 1",
EnergyProfile.EVCONNECTOR_TYPE_COMBO_2 to "Combined Charging System Combo 2",
EnergyProfile.EVCONNECTOR_TYPE_GBT to "GBT_AC Fast Charging Standard",
EnergyProfile.EVCONNECTOR_TYPE_GBT_DC to "GBT_DC Fast Charging Standard",
EnergyProfile.EVCONNECTOR_TYPE_J1772 to "Connector type SAE J1772",
EnergyProfile.EVCONNECTOR_TYPE_MENNEKES to "IEC 62196 Type 2 connector",
EnergyProfile.EVCONNECTOR_TYPE_OTHER to "other",
EnergyProfile.EVCONNECTOR_TYPE_SCAME to "IEC_TYPE_3_AC connector",
EnergyProfile.EVCONNECTOR_TYPE_TESLA_HPWC to "High Power Wall Charger of Tesla",
EnergyProfile.EVCONNECTOR_TYPE_TESLA_ROADSTER to "Connector of Tesla Roadster",
EnergyProfile.EVCONNECTOR_TYPE_TESLA_SUPERCHARGER to "Supercharger of Tesla",
EnergyProfile.EVCONNECTOR_TYPE_UNKNOWN to STATE_UNKNOWN
)
override val name: Int
get() = R.string.sensor_name_car
@ -195,6 +229,7 @@ class CarSensorManager :
}
}
@Suppress("KotlinConstantConditions")
override fun hasSensor(context: Context): Boolean {
this.latestContext = context.applicationContext
@ -239,12 +274,23 @@ class CarSensorManager :
} else {
carSensorsList.forEach {
if (isEnabled(context, it)) {
val attrs = if (it.sensor.id == fuelType.sensor.id || it.sensor.id == evConnector.sensor.id) {
mapOf(
"options" to when (it.sensor.id) {
fuelType.sensor.id -> fuelTypeMap.values.toList()
evConnector.sensor.id -> evTypeMap.values.toList()
else -> {} // unreachable
}
)
} else {
mapOf()
}
onSensorUpdated(
context,
it.sensor,
STATE_UNAVAILABLE,
it.sensor.statelessIcon,
mapOf()
attrs
)
}
}
@ -420,7 +466,8 @@ class CarSensorManager :
if (fuelTypeStatus == "success") getFuelType(data.fuelTypes.value!!) else STATE_UNKNOWN,
fuelType.sensor.statelessIcon,
mapOf(
"status" to fuelTypeStatus
"status" to fuelTypeStatus,
"options" to fuelTypeMap.values.toList()
),
forceUpdate = true
)
@ -432,7 +479,8 @@ class CarSensorManager :
if (evConnectorTypeStatus == "success") getEvConnectorType(data.evConnectorTypes.value!!) else STATE_UNKNOWN,
evConnector.sensor.statelessIcon,
mapOf(
"status" to evConnectorTypeStatus
"status" to evConnectorTypeStatus,
"options" to evTypeMap.values.toList()
),
forceUpdate = true
)
@ -452,22 +500,7 @@ class CarSensorManager :
private fun getFuelType(values: List<Int>): String {
val fuelTypeList = emptyList<String>().toMutableList()
values.forEach {
fuelTypeList += when (it) {
EnergyProfile.FUEL_TYPE_BIODIESEL -> "Biodiesel"
EnergyProfile.FUEL_TYPE_CNG -> "Compressed natural gas"
EnergyProfile.FUEL_TYPE_DIESEL_1 -> "#1 Grade Diesel"
EnergyProfile.FUEL_TYPE_DIESEL_2 -> "#2 Grade Diesel"
EnergyProfile.FUEL_TYPE_E85 -> "85% ethanol/gasoline blend"
EnergyProfile.FUEL_TYPE_ELECTRIC -> "Electric"
EnergyProfile.FUEL_TYPE_HYDROGEN -> "Hydrogen fuel cell"
EnergyProfile.FUEL_TYPE_LEADED -> "Leaded gasoline"
EnergyProfile.FUEL_TYPE_LNG -> "Liquified natural gas"
EnergyProfile.FUEL_TYPE_LPG -> "Liquified petroleum gas"
EnergyProfile.FUEL_TYPE_OTHER -> "Other"
EnergyProfile.FUEL_TYPE_UNKNOWN -> STATE_UNKNOWN
EnergyProfile.FUEL_TYPE_UNLEADED -> "Unleaded gasoline"
else -> STATE_UNKNOWN
}
fuelTypeList += fuelTypeMap.getOrDefault(it, STATE_UNKNOWN)
}
return fuelTypeList.toString()
}
@ -475,22 +508,7 @@ class CarSensorManager :
private fun getEvConnectorType(values: List<Int>): String {
val evConnectorList = emptyList<String>().toMutableList()
values.forEach {
evConnectorList += when (it) {
EnergyProfile.EVCONNECTOR_TYPE_CHADEMO -> "CHAdeMo fast charger connector"
EnergyProfile.EVCONNECTOR_TYPE_COMBO_1 -> "Combined Charging System Combo 1"
EnergyProfile.EVCONNECTOR_TYPE_COMBO_2 -> "Combined Charging System Combo 2"
EnergyProfile.EVCONNECTOR_TYPE_GBT -> "GBT_AC Fast Charging Standard"
EnergyProfile.EVCONNECTOR_TYPE_GBT_DC -> "GBT_DC Fast Charging Standard"
EnergyProfile.EVCONNECTOR_TYPE_J1772 -> "Connector type SAE J1772"
EnergyProfile.EVCONNECTOR_TYPE_MENNEKES -> "IEC 62196 Type 2 connector"
EnergyProfile.EVCONNECTOR_TYPE_OTHER -> "other"
EnergyProfile.EVCONNECTOR_TYPE_SCAME -> "IEC_TYPE_3_AC connector"
EnergyProfile.EVCONNECTOR_TYPE_TESLA_HPWC -> "High Power Wall Charger of Tesla"
EnergyProfile.EVCONNECTOR_TYPE_TESLA_ROADSTER -> "Connector of Tesla Roadster"
EnergyProfile.EVCONNECTOR_TYPE_TESLA_SUPERCHARGER -> "Supercharger of Tesla"
EnergyProfile.EVCONNECTOR_TYPE_UNKNOWN -> STATE_UNKNOWN
else -> STATE_UNKNOWN
}
evConnectorList += evTypeMap.getOrDefault(it, STATE_UNKNOWN)
}
return evConnectorList.toString()
}

View File

@ -64,6 +64,7 @@ class NotificationSensorManager : NotificationListenerService(), SensorManager {
commonR.string.basic_sensor_name_media_session,
commonR.string.sensor_description_media_session,
"mdi:play-circle",
deviceClass = "enum",
docsLink = "https://companion.home-assistant.io/docs/core/sensors#media-session-sensor"
)
}
@ -260,6 +261,21 @@ class NotificationSensorManager : NotificationListenerService(), SensorManager {
}
}
private val mediaStates = mapOf(
PlaybackState.STATE_PLAYING to "Playing",
PlaybackState.STATE_PAUSED to "Paused",
PlaybackState.STATE_STOPPED to "Stopped",
PlaybackState.STATE_BUFFERING to "Buffering",
PlaybackState.STATE_CONNECTING to "Connecting",
PlaybackState.STATE_ERROR to "Error",
PlaybackState.STATE_FAST_FORWARDING to "Fast Forwarding",
PlaybackState.STATE_NONE to "None",
PlaybackState.STATE_REWINDING to "Rewinding",
PlaybackState.STATE_SKIPPING_TO_NEXT to "Skip to Next",
PlaybackState.STATE_SKIPPING_TO_PREVIOUS to "Skip to Previous",
PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM to "Skip to Queue Item"
)
private fun updateMediaSession(context: Context) {
if (!isEnabled(context, mediaSession)) {
return
@ -283,7 +299,10 @@ class NotificationSensorManager : NotificationListenerService(), SensorManager {
)
}
}
attr += mapOf("total_media_session_count" to sessionCount)
attr += mapOf(
"total_media_session_count" to sessionCount,
"options" to mediaStates.values.toList()
)
onSensorUpdated(
context,
mediaSession,
@ -295,21 +314,7 @@ class NotificationSensorManager : NotificationListenerService(), SensorManager {
}
private fun getPlaybackState(state: Int?): String {
return when (state) {
PlaybackState.STATE_PLAYING -> "Playing"
PlaybackState.STATE_PAUSED -> "Paused"
PlaybackState.STATE_STOPPED -> "Stopped"
PlaybackState.STATE_BUFFERING -> "Buffering"
PlaybackState.STATE_CONNECTING -> "Connecting"
PlaybackState.STATE_ERROR -> "Error"
PlaybackState.STATE_FAST_FORWARDING -> "Fast Forwarding"
PlaybackState.STATE_NONE -> "None"
PlaybackState.STATE_REWINDING -> "Rewinding"
PlaybackState.STATE_SKIPPING_TO_NEXT -> "Skip to Next"
PlaybackState.STATE_SKIPPING_TO_PREVIOUS -> "Skip to Previous"
PlaybackState.STATE_SKIPPING_TO_QUEUE_ITEM -> "Skip to Queue Item"
else -> STATE_UNKNOWN
}
return mediaStates.getOrDefault(state ?: PlaybackState.STATE_NONE, STATE_UNKNOWN)
}
/**

View File

@ -702,6 +702,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
val canRegisterEntityDisabledState = server.version?.isAtLeast(2022, 6, 0) == true
val canRegisterDeviceClassDistance = server.version?.isAtLeast(2022, 10, 0) == true
val canRegisterNullProperties = server.version?.isAtLeast(2023, 2, 0) == true
val canRegisterDeviceClassEnum = server.version?.isAtLeast(2023, 1, 0) == true
val registrationData = SensorRegistrationRequest(
sensorRegistration.uniqueId,
@ -718,6 +719,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
sensorRegistration.name,
when (sensorRegistration.deviceClass) {
"distance" -> if (canRegisterDeviceClassDistance) sensorRegistration.deviceClass else null
"enum" -> if (canRegisterDeviceClassEnum) sensorRegistration.deviceClass else null
else -> sensorRegistration.deviceClass
},
sensorRegistration.unitOfMeasurement,

View File

@ -79,6 +79,7 @@ abstract class AppSensorManagerBase : SensorManager {
commonR.string.basic_sensor_name_app_standby,
commonR.string.sensor_description_app_standby,
"mdi:android",
deviceClass = "enum",
docsLink = "https://companion.home-assistant.io/docs/core/sensors#app-usage-sensors",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)
@ -89,6 +90,7 @@ abstract class AppSensorManagerBase : SensorManager {
commonR.string.basic_sensor_name_app_importance,
commonR.string.sensor_description_app_importance,
"mdi:android",
deviceClass = "enum",
docsLink = "https://companion.home-assistant.io/docs/core/sensors#app-importance-sensor",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)
@ -265,7 +267,9 @@ abstract class AppSensorManagerBase : SensorManager {
app_standby_bucket,
appStandbyBucket,
app_standby_bucket.statelessIcon,
mapOf()
mapOf(
"options" to listOf("active", "frequent", "rare", "restricted", "working_set", "never")
)
)
}
@ -319,7 +323,12 @@ abstract class AppSensorManagerBase : SensorManager {
app_importance,
importance,
app_importance.statelessIcon,
mapOf()
mapOf(
"options" to listOf(
"cached", "cant_save_state", "foreground", "foreground_service", "gone",
"perceptible", "service", "top_sleeping", "visible", "not_running"
)
)
)
}
}

View File

@ -20,6 +20,7 @@ class AudioSensorManager : SensorManager {
commonR.string.sensor_name_ringer_mode,
commonR.string.sensor_description_audio_sensor,
"mdi:volume-high",
deviceClass = "enum",
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)
private val audioState = SensorManager.BasicSensor(
@ -27,7 +28,8 @@ class AudioSensorManager : SensorManager {
"sensor",
commonR.string.sensor_name_audio_mode,
commonR.string.sensor_description_audio_mode,
"mdi:volume-high"
"mdi:volume-high",
deviceClass = "enum"
)
private val headphoneState = SensorManager.BasicSensor(
"headphone_state",
@ -212,7 +214,9 @@ class AudioSensorManager : SensorManager {
audioSensor,
ringerMode,
icon,
mapOf()
mapOf(
"options" to listOf("normal", "silent", "vibrate")
)
)
}
@ -247,7 +251,12 @@ class AudioSensorManager : SensorManager {
audioState,
audioMode,
icon,
mapOf()
mapOf(
"options" to listOf(
"normal", "ringing", "in_call", "in_communication", "call_screening",
"call_redirect", "communication_redirect"
)
)
)
}

View File

@ -38,6 +38,7 @@ class BatterySensorManager : SensorManager {
commonR.string.basic_sensor_name_battery_state,
commonR.string.sensor_description_battery_state,
"mdi:battery-charging",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT,
enabledByDefault = true
@ -58,6 +59,7 @@ class BatterySensorManager : SensorManager {
commonR.string.basic_sensor_name_charger_type,
commonR.string.sensor_description_charger_type,
"mdi:power-plug",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT,
enabledByDefault = true
@ -68,6 +70,7 @@ class BatterySensorManager : SensorManager {
commonR.string.basic_sensor_name_battery_health,
commonR.string.sensor_description_battery_health,
"mdi:battery-heart-variant",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)
@ -223,7 +226,9 @@ class BatterySensorManager : SensorManager {
batteryState,
chargingStatus,
icon,
mapOf()
mapOf(
"options" to listOf("charging", "discharging", "full", "not_charging")
)
)
}
@ -262,7 +267,9 @@ class BatterySensorManager : SensorManager {
chargerTypeState,
chargerType,
icon,
mapOf()
mapOf(
"options" to listOf("ac", "usb", "wireless", "dock", "none")
)
)
}
@ -282,7 +289,9 @@ class BatterySensorManager : SensorManager {
batteryHealthState,
batteryHealth,
icon,
mapOf()
mapOf(
"options" to listOf("cold", "dead", "good", "overheated", "over_voltage", "failed")
)
)
}

View File

@ -89,6 +89,7 @@ class BluetoothSensorManager : SensorManager {
commonR.string.basic_sensor_name_bluetooth_ble_emitter,
commonR.string.sensor_description_bluetooth_ble_emitter,
"mdi:bluetooth",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)
@ -100,6 +101,7 @@ class BluetoothSensorManager : SensorManager {
commonR.string.basic_sensor_name_bluetooth_ble_beacon_monitor,
commonR.string.sensor_description_bluetooth_ble_beacon_monitor,
"mdi:bluetooth",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.CUSTOM
)
@ -375,7 +377,8 @@ class BluetoothSensorManager : SensorManager {
"Transmitting power" to bleTransmitterDevice.transmitPowerSetting,
"Advertise mode" to bleTransmitterDevice.advertiseModeSetting,
"Measured power" to bleTransmitterDevice.measuredPowerSetting,
"Supports transmitter" to supportsTransmitter(context)
"Supports transmitter" to supportsTransmitter(context),
"options" to listOf("Transmitting", "Bluetooth is turned off", "Stopped", "Unable to transmit")
)
)
}
@ -402,7 +405,9 @@ class BluetoothSensorManager : SensorManager {
beaconMonitor,
state,
icon,
attr,
attr.plus(
"options" to listOf("Monitoring", "Stopped", "Bluetooth is turned off")
),
forceUpdate = true
)
}

View File

@ -21,6 +21,7 @@ class DNDSensorManager : SensorManager {
commonR.string.sensor_name_dnd,
commonR.string.sensor_description_dnd_sensor,
"mdi:minus-circle",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)
@ -77,7 +78,9 @@ class DNDSensorManager : SensorManager {
dndSensor,
state,
dndSensor.statelessIcon,
mapOf()
mapOf(
"options" to listOf("alarms_only", "off", "priority_only", "total_silence")
)
)
}
}

View File

@ -137,6 +137,7 @@ class NetworkSensorManager : SensorManager {
commonR.string.basic_sensor_name_network_type,
commonR.string.sensor_description_network_type,
"mdi:network",
deviceClass = "enum",
docsLink = "https://companion.home-assistant.io/docs/core/sensors#network-type-sensor",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT
@ -615,7 +616,8 @@ class NetworkSensorManager : SensorManager {
networkCapability,
icon,
mapOf(
"metered" to metered
"metered" to metered,
"options" to listOf("bluetooth", "cellular", "ethernet", "lowpan", "usb", "vpn", "wifi", "wifi_aware")
)
)
}

View File

@ -24,6 +24,7 @@ class PhoneStateSensorManager : SensorManager {
commonR.string.basic_sensor_name_phone,
commonR.string.sensor_description_phone_state,
"mdi:phone",
deviceClass = "enum",
docsLink = "https://companion.home-assistant.io/docs/core/sensors#phone-state-sensor",
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)
@ -111,7 +112,9 @@ class PhoneStateSensorManager : SensorManager {
phoneState,
state,
phoneIcon,
mapOf()
mapOf(
"options" to listOf("idle", "ringing", "offhook")
)
)
}

View File

@ -39,6 +39,7 @@ class HealthServicesSensorManager : SensorManager {
commonR.string.sensor_name_activity_state,
commonR.string.sensor_description_activity_state,
"mdi:account",
deviceClass = "enum",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)
@ -205,7 +206,8 @@ class HealthServicesSensorManager : SensorManager {
getActivityIcon(info),
mapOf(
"time" to info.stateChangeTime,
"exercise_type" to info.exerciseInfo?.exerciseType?.name
"exercise_type" to info.exerciseInfo?.exerciseType?.name,
"options" to listOf("asleep", "passive", "exercise")
),
forceUpdate = forceUpdate
)