mirror of
https://github.com/home-assistant/android
synced 2024-10-02 22:34:46 +00:00
Add ability for ClimateControl Card to cycle through entity states (#4142)
* Add ability for ClimateControl Card to cycle through entity states * Fix ktlint issue * Set `currentMode` after sending request for cycling through modes * Display thermostat always as "on" * Use "toggle" string from widget_tap_action_toggle * Use hashMap to save states of entities as we're in a singleton * Include support for colliding entityIds when using multi server within ClimateControl * Add comment why ToggleRangeTemplate is always set to checked
This commit is contained in:
parent
f006127b01
commit
45e0ca9caa
|
@ -15,7 +15,6 @@ import io.homeassistant.companion.android.R
|
|||
import io.homeassistant.companion.android.common.R as commonR
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.common.util.STATE_UNAVAILABLE
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -32,11 +31,10 @@ object CameraControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
val image = if (baseUrl != null && (entity.attributes["entity_picture"] as? String)?.isNotBlank() == true) {
|
||||
getThumbnail(baseUrl + entity.attributes["entity_picture"] as String)
|
||||
val image = if (info.baseUrl != null && (entity.attributes["entity_picture"] as? String)?.isNotBlank() == true) {
|
||||
getThumbnail(info.baseUrl + entity.attributes["entity_picture"] as String)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
@ -4,19 +4,22 @@ import android.content.Context
|
|||
import android.os.Build
|
||||
import android.service.controls.Control
|
||||
import android.service.controls.DeviceTypes
|
||||
import android.service.controls.actions.BooleanAction
|
||||
import android.service.controls.actions.ControlAction
|
||||
import android.service.controls.actions.FloatAction
|
||||
import android.service.controls.actions.ModeAction
|
||||
import android.service.controls.templates.RangeTemplate
|
||||
import android.service.controls.templates.TemperatureControlTemplate
|
||||
import android.service.controls.templates.ToggleRangeTemplate
|
||||
import androidx.annotation.RequiresApi
|
||||
import io.homeassistant.companion.android.common.R as commonR
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
object ClimateControl : HaControl {
|
||||
private data class ClimateState(val currentMode: String, val supportedModes: ArrayList<String>)
|
||||
|
||||
private const val SUPPORT_TARGET_TEMPERATURE = 1
|
||||
private const val SUPPORT_TARGET_TEMPERATURE_RANGE = 2
|
||||
private val temperatureControlModes = mapOf(
|
||||
|
@ -31,13 +34,13 @@ object ClimateControl : HaControl {
|
|||
"heat_cool" to TemperatureControlTemplate.FLAG_MODE_HEAT_COOL,
|
||||
"off" to TemperatureControlTemplate.FLAG_MODE_OFF
|
||||
)
|
||||
private val climateStates = HashMap<String, ClimateState>()
|
||||
|
||||
override fun provideControlFeatures(
|
||||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
val minValue = (entity.attributes["min_temp"] as? Number)?.toFloat() ?: 0f
|
||||
val maxValue = (entity.attributes["max_temp"] as? Number)?.toFloat() ?: 100f
|
||||
|
@ -60,7 +63,7 @@ object ClimateControl : HaControl {
|
|||
}
|
||||
val temperatureFormatSize = if (temperatureStepSize < 1f) "1" else "0"
|
||||
val rangeTemplate = RangeTemplate(
|
||||
entity.entityId,
|
||||
info.systemId,
|
||||
minValue,
|
||||
maxValue,
|
||||
currentValue,
|
||||
|
@ -68,14 +71,24 @@ object ClimateControl : HaControl {
|
|||
"%.${temperatureFormatSize}f $temperatureUnit"
|
||||
)
|
||||
if (entityShouldBePresentedAsThermostat(entity)) {
|
||||
val state = ClimateState(entity.state, ArrayList())
|
||||
val toggleRangeTemplate = ToggleRangeTemplate(
|
||||
info.systemId + "_range",
|
||||
// Set checked to true to always show the temperature indicator, regardless of climate mode
|
||||
true,
|
||||
context.getString(commonR.string.widget_tap_action_toggle),
|
||||
rangeTemplate
|
||||
)
|
||||
var modesFlag = 0
|
||||
(entity.attributes["hvac_modes"] as? List<String>)?.forEach {
|
||||
modesFlag = modesFlag or temperatureControlModeFlags[it]!!
|
||||
state.supportedModes.add(it)
|
||||
}
|
||||
this.climateStates[info.systemId] = state
|
||||
control.setControlTemplate(
|
||||
TemperatureControlTemplate(
|
||||
entity.entityId,
|
||||
rangeTemplate,
|
||||
info.systemId,
|
||||
toggleRangeTemplate,
|
||||
temperatureControlModes[entity.state]!!,
|
||||
temperatureControlModes[entity.state]!!,
|
||||
modesFlag
|
||||
|
@ -102,13 +115,18 @@ object ClimateControl : HaControl {
|
|||
integrationRepository: IntegrationRepository,
|
||||
action: ControlAction
|
||||
): Boolean {
|
||||
val entityStr: String = if (action.templateId.split(".").size > 2) {
|
||||
action.templateId.split(".", limit = 2)[1]
|
||||
} else {
|
||||
action.templateId
|
||||
}
|
||||
return when (action) {
|
||||
is FloatAction -> {
|
||||
integrationRepository.callService(
|
||||
action.templateId.split(".")[0],
|
||||
entityStr.split(".")[0],
|
||||
"set_temperature",
|
||||
hashMapOf(
|
||||
"entity_id" to action.templateId,
|
||||
"entity_id" to entityStr,
|
||||
"temperature" to (action as? FloatAction)?.newValue.toString()
|
||||
)
|
||||
)
|
||||
|
@ -119,7 +137,7 @@ object ClimateControl : HaControl {
|
|||
action.templateId.split(".")[0],
|
||||
"set_hvac_mode",
|
||||
hashMapOf(
|
||||
"entity_id" to action.templateId,
|
||||
"entity_id" to entityStr,
|
||||
"hvac_mode" to (
|
||||
temperatureControlModes.entries.find {
|
||||
it.value == ((action as? ModeAction)?.newMode ?: -1)
|
||||
|
@ -129,6 +147,23 @@ object ClimateControl : HaControl {
|
|||
)
|
||||
true
|
||||
}
|
||||
is BooleanAction -> {
|
||||
if (this.climateStates[action.templateId] == null) {
|
||||
return false
|
||||
}
|
||||
val supportedModes = this.climateStates[action.templateId]!!.supportedModes
|
||||
val currentMode = this.climateStates[action.templateId]!!.currentMode
|
||||
val nextMode = (supportedModes.indexOf(currentMode) + 1) % supportedModes.count()
|
||||
integrationRepository.callService(
|
||||
entityStr.split(".")[0],
|
||||
"set_hvac_mode",
|
||||
hashMapOf(
|
||||
"entity_id" to entityStr,
|
||||
"hvac_mode" to supportedModes[nextMode]
|
||||
)
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import io.homeassistant.companion.android.common.data.integration.Entity
|
|||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.getCoverPosition
|
||||
import io.homeassistant.companion.android.common.data.integration.isActive
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
object CoverControl : HaControl {
|
||||
|
@ -26,8 +25,7 @@ object CoverControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
val position = entity.getCoverPosition()
|
||||
control.setControlTemplate(
|
||||
|
|
|
@ -11,7 +11,6 @@ import io.homeassistant.companion.android.common.R as commonR
|
|||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.common.util.capitalize
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -21,8 +20,7 @@ object DefaultButtonControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
control.setStatusText("")
|
||||
control.setControlTemplate(
|
||||
|
|
|
@ -11,7 +11,6 @@ import androidx.annotation.RequiresApi
|
|||
import io.homeassistant.companion.android.common.R as commonR
|
||||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
|
@ -20,8 +19,7 @@ object DefaultSliderControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
control.setStatusText("")
|
||||
control.setControlTemplate(
|
||||
|
|
|
@ -14,7 +14,6 @@ import io.homeassistant.companion.android.common.data.integration.Entity
|
|||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.isActive
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.common.util.capitalize
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -24,8 +23,7 @@ object DefaultSwitchControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
control.setControlTemplate(
|
||||
ToggleTemplate(
|
||||
|
|
|
@ -18,7 +18,6 @@ import io.homeassistant.companion.android.common.data.integration.IntegrationRep
|
|||
import io.homeassistant.companion.android.common.data.integration.getFanSpeed
|
||||
import io.homeassistant.companion.android.common.data.integration.isActive
|
||||
import io.homeassistant.companion.android.common.data.integration.supportsFanSetSpeed
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
object FanControl : HaControl {
|
||||
|
@ -26,8 +25,7 @@ object FanControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
if (entity.supportsFanSetSpeed()) {
|
||||
val position = entity.getFanSpeed()
|
||||
|
|
|
@ -17,7 +17,6 @@ import io.homeassistant.companion.android.common.data.integration.Entity
|
|||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.integration.friendlyState
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.webview.WebViewActivity
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
|
@ -77,15 +76,14 @@ interface HaControl {
|
|||
}
|
||||
}
|
||||
|
||||
return provideControlFeatures(context, control, entity, info.area, info.baseUrl).build()
|
||||
return provideControlFeatures(context, control, entity, info).build()
|
||||
}
|
||||
|
||||
fun provideControlFeatures(
|
||||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder
|
||||
|
||||
fun getDeviceType(entity: Entity<Map<String, Any>>): Int
|
||||
|
|
|
@ -10,7 +10,6 @@ import androidx.annotation.RequiresApi
|
|||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.domain
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.common.util.capitalize
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -20,8 +19,7 @@ object HaFailedControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
control.setStatus(if (entity.state == "notfound") Control.STATUS_NOT_FOUND else Control.STATUS_ERROR)
|
||||
control.setStatusText("")
|
||||
|
|
|
@ -18,7 +18,6 @@ import io.homeassistant.companion.android.common.data.integration.IntegrationRep
|
|||
import io.homeassistant.companion.android.common.data.integration.getLightBrightness
|
||||
import io.homeassistant.companion.android.common.data.integration.isActive
|
||||
import io.homeassistant.companion.android.common.data.integration.supportsLightBrightness
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
object LightControl : HaControl {
|
||||
|
@ -26,8 +25,7 @@ object LightControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
val position = entity.getLightBrightness()
|
||||
control.setControlTemplate(
|
||||
|
|
|
@ -13,7 +13,6 @@ import io.homeassistant.companion.android.common.R as commonR
|
|||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.isActive
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
object LockControl : HaControl {
|
||||
|
@ -21,8 +20,7 @@ object LockControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
control.setControlTemplate(
|
||||
ToggleTemplate(
|
||||
|
|
|
@ -13,7 +13,6 @@ import io.homeassistant.companion.android.common.R as commonR
|
|||
import io.homeassistant.companion.android.common.data.integration.Entity
|
||||
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
|
||||
import io.homeassistant.companion.android.common.data.integration.isActive
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
object VacuumControl : HaControl {
|
||||
|
@ -24,8 +23,7 @@ object VacuumControl : HaControl {
|
|||
context: Context,
|
||||
control: Control.StatefulBuilder,
|
||||
entity: Entity<Map<String, Any>>,
|
||||
area: AreaRegistryResponse?,
|
||||
baseUrl: String?
|
||||
info: HaControlInfo
|
||||
): Control.StatefulBuilder {
|
||||
entitySupportedFeatures = entity.attributes["supported_features"] as Int
|
||||
control.setControlTemplate(
|
||||
|
|
Loading…
Reference in a new issue