Add fan speed to Wear OS detail panel (#2332)

* Add fan speed detail panel to Wear OS

 - Added a fan speed slider for entities that support setting the fan speed
 - Adjust light brightness string to include percentage symbol

* Rename extension function
This commit is contained in:
Joris Pelgröm 2022-03-04 00:55:16 +01:00 committed by GitHub
parent 3de198897d
commit 27b02a0be5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 3 deletions

View file

@ -14,6 +14,7 @@ import android.service.controls.templates.ToggleTemplate
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.supportsFanSetSpeed
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
import kotlinx.coroutines.runBlocking
import io.homeassistant.companion.android.common.R as commonR
@ -21,14 +22,13 @@ import io.homeassistant.companion.android.common.R as commonR
@RequiresApi(Build.VERSION_CODES.R)
class FanControl {
companion object : HaControl {
private const val SUPPORT_SET_SPEED = 1
override fun provideControlFeatures(
context: Context,
control: Control.StatefulBuilder,
entity: Entity<Map<String, Any>>,
area: AreaRegistryResponse?
): Control.StatefulBuilder {
if ((entity.attributes["supported_features"] as Int) and SUPPORT_SET_SPEED == SUPPORT_SET_SPEED) {
if (entity.supportsFanSetSpeed()) {
val minValue = 0f
val maxValue = 100f
var currentValue =

View file

@ -15,6 +15,7 @@ data class Entity<T>(
object EntityExt {
const val TAG = "EntityExt"
const val FAN_SUPPORT_SET_SPEED = 1
const val LIGHT_MODE_COLOR_TEMP = "color_temp"
val LIGHT_MODE_NO_BRIGHTNESS_SUPPORT = listOf("unknown", "onoff")
const val LIGHT_SUPPORT_BRIGHTNESS_DEPR = 1
@ -24,6 +25,16 @@ object EntityExt {
val <T> Entity<T>.domain: String
get() = this.entityId.split(".")[0]
fun <T> Entity<T>.supportsFanSetSpeed(): Boolean {
return try {
if (domain != "fan") return false
((attributes as Map<*, *>)["supported_features"] as Int) and EntityExt.FAN_SUPPORT_SET_SPEED == EntityExt.FAN_SUPPORT_SET_SPEED
} catch (e: Exception) {
Log.e(EntityExt.TAG, "Unable to get supportsFanSetSpeed", e)
false
}
}
fun <T> Entity<T>.supportsLightBrightness(): Boolean {
return try {
if (domain != "light") return false

View file

@ -89,7 +89,7 @@
<string name="biometric_message">Unlock using your biometric or screenlock credential</string>
<string name="biometric_set_title">Confirm to continue</string>
<string name="biometric_title">Home Assistant is locked</string>
<string name="brightness">Brightness: %1$d</string>
<string name="brightness">Brightness: %1$d%%</string>
<string name="broadcast_intent_error">Unable to send broadcast intent, please check the command format</string>
<string name="buttons">Buttons</string>
<string name="button_forward">Next</string>
@ -604,6 +604,7 @@
<string name="show_share_logs">Show and Share Logs</string>
<string name="sign_in_on_phone">Sign in on phone</string>
<string name="skip">Skip</string>
<string name="speed">Speed: %1$d%%</string>
<string name="state_auto">Auto</string>
<string name="state_cleaning">Cleaning</string>
<string name="state_closed">Closed</string>

View file

@ -17,6 +17,7 @@ interface HomePresenter {
fun onViewReady()
suspend fun onEntityClicked(entityId: String, state: String)
suspend fun onFanSpeedChanged(entityId: String, speed: Float)
suspend fun onBrightnessChanged(entityId: String, brightness: Float)
suspend fun onColorTempChanged(entityId: String, colorTemp: Float)
fun onLogoutClicked()

View file

@ -102,6 +102,17 @@ class HomePresenterImpl @Inject constructor(
)
}
override suspend fun onFanSpeedChanged(entityId: String, speed: Float) {
integrationUseCase.callService(
entityId.split(".")[0],
"set_percentage",
hashMapOf(
"entity_id" to entityId,
"percentage" to speed.toInt()
)
)
}
override suspend fun onBrightnessChanged(entityId: String, brightness: Float) {
integrationUseCase.callService(
entityId.split(".")[0],

View file

@ -239,6 +239,11 @@ class MainViewModel @Inject constructor(application: Application) : AndroidViewM
homePresenter.onEntityClicked(entityId, state)
}
}
fun setFanSpeed(entityId: String, speed: Float) {
viewModelScope.launch {
homePresenter.onFanSpeedChanged(entityId, speed)
}
}
fun setBrightness(entityId: String, brightness: Float) {
viewModelScope.launch {
homePresenter.onBrightnessChanged(entityId, brightness)

View file

@ -25,6 +25,7 @@ import io.homeassistant.companion.android.common.R
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.EntityExt
import io.homeassistant.companion.android.common.data.integration.domain
import io.homeassistant.companion.android.common.data.integration.supportsFanSetSpeed
import io.homeassistant.companion.android.common.data.integration.supportsLightBrightness
import io.homeassistant.companion.android.common.data.integration.supportsLightColorTemperature
import io.homeassistant.companion.android.home.HomePresenterImpl
@ -37,6 +38,7 @@ import java.text.DateFormat
fun DetailsPanelView(
entity: Entity<*>,
onEntityToggled: (String, String) -> Unit,
onFanSpeedChanged: (Float) -> Unit,
onBrightnessChanged: (Float) -> Unit,
onColorTempChanged: (Float) -> Unit
) {
@ -66,6 +68,13 @@ fun DetailsPanelView(
}
}
if (entity.domain == "fan") {
if (entity.supportsFanSetSpeed()) {
item {
FanSpeedSlider(attributes, onFanSpeedChanged)
}
}
}
if (entity.domain == "light") {
if (entity.supportsLightBrightness()) {
item {
@ -121,6 +130,45 @@ fun DetailsPanelView(
}
}
@Composable
fun FanSpeedSlider(attributes: Map<*, *>, onFanSpeedChanged: (Float) -> Unit) {
val minValue = 0f
val maxValue = 100f
var currentValue = (attributes["percentage"] as? Number)?.toFloat() ?: 0f
if (currentValue < minValue)
currentValue = minValue
if (currentValue > maxValue)
currentValue = maxValue
Column {
Text(
stringResource(R.string.speed, currentValue.toInt()),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp)
)
InlineSlider(
value = currentValue,
onValueChange = onFanSpeedChanged,
steps = 9,
valueRange = minValue..maxValue,
decreaseIcon = {
Image(
asset = CommunityMaterial.Icon2.cmd_fan_minus,
colorFilter = ColorFilter.tint(Color.White)
)
},
increaseIcon = {
Image(
asset = CommunityMaterial.Icon2.cmd_fan_plus,
colorFilter = ColorFilter.tint(Color.White)
)
},
modifier = Modifier.padding(bottom = 8.dp, top = 2.dp)
)
}
}
@Composable
fun BrightnessSlider(attributes: Map<*, *>, onBrightnessChanged: (Float) -> Unit) {
val minValue = 0f

View file

@ -112,6 +112,12 @@ fun LoadHomePage(
onEntityToggled = { entityId, state ->
mainViewModel.toggleEntity(entityId, state)
},
onFanSpeedChanged = { speed ->
mainViewModel.setFanSpeed(
entity.entityId,
speed
)
},
onBrightnessChanged = { brightness ->
mainViewModel.setBrightness(
entity.entityId,