mirror of
https://github.com/home-assistant/android
synced 2024-10-06 16:19:38 +00:00
Merge branch 'master' into HA_Entity_Loading
This commit is contained in:
commit
496cd100f2
|
@ -947,7 +947,7 @@ class LocationSensorManager : LocationSensorManagerBase() {
|
|||
val configuredZones = getZones(serverId, forceRefresh = true)
|
||||
configuredZones.forEach {
|
||||
addGeofenceToBuilder(geofencingRequestBuilder, serverId, it)
|
||||
if (highAccuracyTriggerRange > 0 && highAccuracyZones.contains(it.entityId)) {
|
||||
if (highAccuracyTriggerRange > 0 && highAccuracyZones.contains("${serverId}_${it.entityId}")) {
|
||||
addGeofenceToBuilder(geofencingRequestBuilder, serverId, it, highAccuracyTriggerRange)
|
||||
}
|
||||
}
|
||||
|
@ -963,7 +963,7 @@ class LocationSensorManager : LocationSensorManagerBase() {
|
|||
zone: Entity<ZoneAttributes>,
|
||||
triggerRange: Int = 0
|
||||
) {
|
||||
val postRequestId = if (triggerRange > 0)"_expanded" else ""
|
||||
val postRequestId = if (triggerRange > 0) "_expanded" else ""
|
||||
geofencingRequestBuilder
|
||||
.addGeofence(
|
||||
Geofence.Builder()
|
||||
|
|
|
@ -394,7 +394,7 @@ class SensorDetailViewModel @Inject constructor(
|
|||
.filter { entries == null || entries.contains(it) }
|
||||
.map {
|
||||
val server = servers.first { s -> s.id == it.split("_")[0].toInt() }
|
||||
val zone = it.split("_")[1]
|
||||
val zone = it.split("_", limit = 2)[1]
|
||||
if (servers.size > 1) "${server.friendlyName}: $zone" else zone
|
||||
}
|
||||
val entriesNotInZones = entries
|
||||
|
|
|
@ -27,6 +27,7 @@ import androidx.core.graphics.toColorInt
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.maltaisn.icondialog.IconDialog
|
||||
import com.maltaisn.icondialog.IconDialogSettings
|
||||
|
@ -134,8 +135,24 @@ class ButtonWidgetConfigureActivity : BaseWidgetConfigureActivity(), IconDialog.
|
|||
val fieldKeys = fields.keys
|
||||
Log.d(TAG, "Fields applicable to this service: $fields")
|
||||
|
||||
if (target !== false) {
|
||||
dynamicFields.add(0, ServiceFieldBinder(serviceText, "entity_id"))
|
||||
val existingServiceData = mutableMapOf<String, Any?>()
|
||||
buttonWidgetDao.get(appWidgetId)?.let { buttonWidget ->
|
||||
if (
|
||||
buttonWidget.serverId != selectedServerId ||
|
||||
"${buttonWidget.domain}.${buttonWidget.service}" != serviceText
|
||||
) {
|
||||
return@let
|
||||
}
|
||||
|
||||
val dbMap: HashMap<String, Any?> = jacksonObjectMapper().readValue(buttonWidget.serviceData)
|
||||
for (item in dbMap) {
|
||||
val value = item.value.toString().replace("[", "").replace("]", "") + if (item.key == "entity_id") ", " else ""
|
||||
existingServiceData[item.key] = value.ifEmpty { null }
|
||||
}
|
||||
}
|
||||
|
||||
if (target != false) {
|
||||
dynamicFields.add(0, ServiceFieldBinder(serviceText, "entity_id", existingServiceData["entity_id"]))
|
||||
}
|
||||
|
||||
fieldKeys.sorted().forEach { fieldKey ->
|
||||
|
@ -145,9 +162,9 @@ class ButtonWidgetConfigureActivity : BaseWidgetConfigureActivity(), IconDialog.
|
|||
// IDs get priority and go at the top, since the other fields
|
||||
// are usually optional but the ID is required
|
||||
if (fieldKey.contains("_id")) {
|
||||
dynamicFields.add(0, ServiceFieldBinder(serviceText, fieldKey))
|
||||
dynamicFields.add(0, ServiceFieldBinder(serviceText, fieldKey, existingServiceData[fieldKey]))
|
||||
} else {
|
||||
dynamicFields.add(ServiceFieldBinder(serviceText, fieldKey))
|
||||
dynamicFields.add(ServiceFieldBinder(serviceText, fieldKey, existingServiceData[fieldKey]))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ interface IntegrationRepository {
|
|||
|
||||
suspend fun shouldNotifySecurityWarning(): Boolean
|
||||
|
||||
suspend fun getConversation(speech: String): String?
|
||||
suspend fun getAssistResponse(speech: String): String?
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
@ -25,13 +25,21 @@ import io.homeassistant.companion.android.common.data.integration.impl.entities.
|
|||
import io.homeassistant.companion.android.common.data.integration.impl.entities.Template
|
||||
import io.homeassistant.companion.android.common.data.integration.impl.entities.UpdateLocationRequest
|
||||
import io.homeassistant.companion.android.common.data.servers.ServerManager
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineEventType
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineIntentEnd
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.GetConfigResponse
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Named
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
class IntegrationRepositoryImpl @AssistedInject constructor(
|
||||
private val integrationService: IntegrationService,
|
||||
|
@ -64,6 +72,8 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
|
|||
private const val APPLOCK_TIMEOUT_GRACE_MS = 1000
|
||||
}
|
||||
|
||||
private val ioScope = CoroutineScope(Dispatchers.IO + Job())
|
||||
|
||||
private val server get() = serverManager.getServer(serverId)!!
|
||||
|
||||
private val webSocketRepository get() = serverManager.webSocketRepository(serverId)
|
||||
|
@ -377,7 +387,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
|
|||
}
|
||||
|
||||
override suspend fun setAppActive(active: Boolean) {
|
||||
if (!active) {
|
||||
if (!active && appActive) {
|
||||
setSessionExpireMillis(System.currentTimeMillis() + (getSessionTimeOut() * 1000) + APPLOCK_TIMEOUT_GRACE_MS)
|
||||
}
|
||||
Log.d(TAG, "setAppActive(): $active")
|
||||
|
@ -523,11 +533,29 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
|
|||
}?.toList()
|
||||
}
|
||||
|
||||
override suspend fun getConversation(speech: String): String? {
|
||||
// TODO: Also send back conversation ID for dialogue
|
||||
val response = webSocketRepository.getConversation(speech)
|
||||
|
||||
return response?.response?.speech?.plain?.get("speech")
|
||||
override suspend fun getAssistResponse(speech: String): String? {
|
||||
return if (server.version?.isAtLeast(2023, 5, 0) == true) {
|
||||
var job: Job? = null
|
||||
val response = suspendCancellableCoroutine { cont ->
|
||||
job = ioScope.launch {
|
||||
webSocketRepository.runAssistPipeline(speech)?.collect {
|
||||
if (!cont.isActive) return@collect
|
||||
when (it.type) {
|
||||
AssistPipelineEventType.INTENT_END ->
|
||||
cont.resume((it.data as AssistPipelineIntentEnd).intentOutput.response.speech.plain["speech"])
|
||||
AssistPipelineEventType.ERROR,
|
||||
AssistPipelineEventType.RUN_END -> cont.resume(null)
|
||||
else -> { /* Do nothing */ }
|
||||
}
|
||||
} ?: cont.resume(null)
|
||||
}
|
||||
}
|
||||
job?.cancel()
|
||||
response
|
||||
} else {
|
||||
val response = webSocketRepository.getConversation(speech)
|
||||
response?.response?.speech?.plain?.get("speech")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getEntities(): List<Entity<Any>>? {
|
||||
|
|
|
@ -5,6 +5,7 @@ import io.homeassistant.companion.android.common.data.integration.impl.entities.
|
|||
import io.homeassistant.companion.android.common.data.websocket.impl.WebSocketRepositoryImpl
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryUpdatedEvent
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineEvent
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.CompressedStateChangedEvent
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.ConversationResponse
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.CurrentUserResponse
|
||||
|
@ -48,7 +49,18 @@ interface WebSocketRepository {
|
|||
suspend fun getThreadDatasets(): List<ThreadDatasetResponse>?
|
||||
suspend fun getThreadDatasetTlv(datasetId: String): ThreadDatasetTlvResponse?
|
||||
suspend fun addThreadDataset(tlv: ByteArray): Boolean
|
||||
|
||||
/**
|
||||
* Get an Assist response for the given text input. For core >= 2023.5, use [runAssistPipeline]
|
||||
* instead.
|
||||
*/
|
||||
suspend fun getConversation(speech: String): ConversationResponse?
|
||||
|
||||
/**
|
||||
* Run the Assist pipeline for the given text input
|
||||
* @return a Flow that will emit all events for the pipeline
|
||||
*/
|
||||
suspend fun runAssistPipeline(text: String): Flow<AssistPipelineEvent>?
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
|
|
|
@ -23,6 +23,11 @@ import io.homeassistant.companion.android.common.data.websocket.WebSocketRequest
|
|||
import io.homeassistant.companion.android.common.data.websocket.WebSocketState
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryUpdatedEvent
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineEvent
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineEventType
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineIntentEnd
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineIntentStart
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AssistPipelineRunStart
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.CompressedStateChangedEvent
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.ConversationResponse
|
||||
import io.homeassistant.companion.android.common.data.websocket.impl.entities.CurrentUserResponse
|
||||
|
@ -81,6 +86,7 @@ class WebSocketRepositoryImpl @AssistedInject constructor(
|
|||
companion object {
|
||||
private const val TAG = "WebSocketRepository"
|
||||
|
||||
private const val SUBSCRIBE_TYPE_ASSIST_PIPELINE_RUN = "assist_pipeline/run"
|
||||
private const val SUBSCRIBE_TYPE_SUBSCRIBE_EVENTS = "subscribe_events"
|
||||
private const val SUBSCRIBE_TYPE_SUBSCRIBE_ENTITIES = "subscribe_entities"
|
||||
private const val SUBSCRIBE_TYPE_SUBSCRIBE_TRIGGER = "subscribe_trigger"
|
||||
|
@ -209,6 +215,18 @@ class WebSocketRepositoryImpl @AssistedInject constructor(
|
|||
return mapResponse(socketResponse)
|
||||
}
|
||||
|
||||
override suspend fun runAssistPipeline(text: String): Flow<AssistPipelineEvent>? =
|
||||
subscribeTo(
|
||||
SUBSCRIBE_TYPE_ASSIST_PIPELINE_RUN,
|
||||
mapOf(
|
||||
"start_stage" to "intent",
|
||||
"end_stage" to "intent",
|
||||
"input" to mapOf(
|
||||
"text" to text
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
override suspend fun getStateChanges(): Flow<StateChangedEvent>? =
|
||||
subscribeToEventsForType(EVENT_STATE_CHANGED)
|
||||
|
||||
|
@ -629,6 +647,21 @@ class WebSocketRepositoryImpl @AssistedInject constructor(
|
|||
Log.w(TAG, "Received no trigger value for trigger subscription, skipping")
|
||||
return
|
||||
}
|
||||
} else if (subscriptionType == SUBSCRIBE_TYPE_ASSIST_PIPELINE_RUN) {
|
||||
val eventType = response.event?.get("type")
|
||||
if (eventType?.isTextual == true) {
|
||||
val eventDataMap = response.event.get("data")
|
||||
val eventData = when (eventType.textValue()) {
|
||||
AssistPipelineEventType.RUN_START -> mapper.convertValue(eventDataMap, AssistPipelineRunStart::class.java)
|
||||
AssistPipelineEventType.INTENT_START -> mapper.convertValue(eventDataMap, AssistPipelineIntentStart::class.java)
|
||||
AssistPipelineEventType.INTENT_END -> mapper.convertValue(eventDataMap, AssistPipelineIntentEnd::class.java)
|
||||
else -> null
|
||||
}
|
||||
AssistPipelineEvent(eventType.textValue(), eventData)
|
||||
} else {
|
||||
Log.w(TAG, "Received Assist pipeline event without type, skipping")
|
||||
return
|
||||
}
|
||||
} else if (eventResponseType != null && eventResponseType.isTextual) {
|
||||
val eventResponseClass = when (eventResponseType.textValue()) {
|
||||
EVENT_STATE_CHANGED ->
|
||||
|
@ -737,17 +770,18 @@ class WebSocketRepositoryImpl @AssistedInject constructor(
|
|||
listOf(mapper.readValue(text))
|
||||
}
|
||||
|
||||
messages.forEach { message ->
|
||||
Log.d(TAG, "Message number ${message.id} received")
|
||||
|
||||
messages.groupBy { it.id }.values.forEach { messagesForId ->
|
||||
ioScope.launch {
|
||||
when (message.type) {
|
||||
"auth_required" -> Log.d(TAG, "Auth Requested")
|
||||
"auth_ok" -> handleAuthComplete(true, message.haVersion)
|
||||
"auth_invalid" -> handleAuthComplete(false, message.haVersion)
|
||||
"pong", "result" -> handleMessage(message)
|
||||
"event" -> handleEvent(message)
|
||||
else -> Log.d(TAG, "Unknown message type: ${message.type}")
|
||||
messagesForId.forEach { message ->
|
||||
Log.d(TAG, "Message number ${message.id} received")
|
||||
when (message.type) {
|
||||
"auth_required" -> Log.d(TAG, "Auth Requested")
|
||||
"auth_ok" -> handleAuthComplete(true, message.haVersion)
|
||||
"auth_invalid" -> handleAuthComplete(false, message.haVersion)
|
||||
"pong", "result" -> handleMessage(message)
|
||||
"event" -> handleEvent(message)
|
||||
else -> Log.d(TAG, "Unknown message type: ${message.type}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package io.homeassistant.companion.android.common.data.websocket.impl.entities
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
|
||||
data class AssistPipelineEvent(
|
||||
val type: String,
|
||||
val data: AssistPipelineEventData?
|
||||
)
|
||||
|
||||
object AssistPipelineEventType {
|
||||
const val RUN_START = "run-start"
|
||||
const val RUN_END = "run-end"
|
||||
const val STT_START = "stt-start"
|
||||
const val STT_END = "stt-end"
|
||||
const val INTENT_START = "intent-start"
|
||||
const val INTENT_END = "intent-end"
|
||||
const val TTS_START = "tts-start"
|
||||
const val TTS_END = "tts-end"
|
||||
const val ERROR = "error"
|
||||
}
|
||||
|
||||
interface AssistPipelineEventData
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class AssistPipelineRunStart(
|
||||
val pipeline: String,
|
||||
val language: String,
|
||||
val runnerData: Map<String, Any?>
|
||||
) : AssistPipelineEventData
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class AssistPipelineIntentStart(
|
||||
val engine: String,
|
||||
val language: String,
|
||||
val intentInput: String
|
||||
) : AssistPipelineEventData
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class AssistPipelineIntentEnd(
|
||||
val intentOutput: ConversationResponse
|
||||
) : AssistPipelineEventData
|
|
@ -0,0 +1,20 @@
|
|||
package io.homeassistant.companion.android.util
|
||||
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.transform
|
||||
|
||||
/**
|
||||
* Emit the first value from a Flow, and then after the period has passed the last item emitted
|
||||
* by the Flow during that period (if different). This ensures throttling/debouncing but also
|
||||
* always receiving the first and last item of the Flow.
|
||||
*
|
||||
* From https://github.com/Kotlin/kotlinx.coroutines/issues/1446#issuecomment-1198103541
|
||||
*/
|
||||
fun <T> Flow<T>.throttleLatest(delayMillis: Long): Flow<T> = this
|
||||
.conflate()
|
||||
.transform {
|
||||
emit(it)
|
||||
delay(delayMillis)
|
||||
}
|
|
@ -1052,7 +1052,9 @@
|
|||
<string name="tile_vibrate">Vibrate when clicked</string>
|
||||
<string name="tile_auth_required">Requires unlocked device</string>
|
||||
<string name="no_results">No results yet</string>
|
||||
<string name="no_conversation_support">You must be at least on Home Assistant 2023.1 and have the conversation integration enabled</string>
|
||||
<string name="no_assist_support">You must be at least on Home Assistant %1$s and have the %2$s integration enabled</string>
|
||||
<string name="no_assist_support_conversation">conversation</string>
|
||||
<string name="no_assist_support_assist_pipeline">Assist pipeline</string>
|
||||
<string name="conversation">Conversation</string>
|
||||
<string name="assist">Assist</string>
|
||||
<string name="assist_log_in">Log in to Home Assistant to start using Assist</string>
|
||||
|
|
|
@ -42,8 +42,8 @@ class ConversationActivity : ComponentActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
lifecycleScope.launch {
|
||||
conversationViewModel.isSupportConversation()
|
||||
if (conversationViewModel.supportsConversation) {
|
||||
conversationViewModel.checkAssistSupport()
|
||||
if (conversationViewModel.supportsAssist) {
|
||||
val searchIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
|
||||
putExtra(
|
||||
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
|
||||
|
|
|
@ -25,7 +25,10 @@ class ConversationViewModel @Inject constructor(
|
|||
var conversationResult by mutableStateOf("")
|
||||
private set
|
||||
|
||||
var supportsConversation by mutableStateOf(false)
|
||||
var supportsAssist by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var useAssistPipeline by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var isHapticEnabled = mutableStateOf(false)
|
||||
|
@ -41,20 +44,28 @@ class ConversationViewModel @Inject constructor(
|
|||
viewModelScope.launch {
|
||||
conversationResult =
|
||||
if (serverManager.isRegistered()) {
|
||||
serverManager.integrationRepository().getConversation(speechResult) ?: ""
|
||||
serverManager.integrationRepository().getAssistResponse(speechResult) ?: ""
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun isSupportConversation() {
|
||||
suspend fun checkAssistSupport() {
|
||||
checkSupportProgress = true
|
||||
isRegistered = serverManager.isRegistered()
|
||||
supportsConversation =
|
||||
serverManager.isRegistered() &&
|
||||
serverManager.integrationRepository().isHomeAssistantVersionAtLeast(2023, 1, 0) &&
|
||||
serverManager.webSocketRepository().getConfig()?.components?.contains("conversation") == true
|
||||
|
||||
if (serverManager.isRegistered()) {
|
||||
val config = serverManager.webSocketRepository().getConfig()
|
||||
val onConversationVersion = serverManager.integrationRepository().isHomeAssistantVersionAtLeast(2023, 1, 0)
|
||||
val onPipelineVersion = serverManager.integrationRepository().isHomeAssistantVersionAtLeast(2023, 5, 0)
|
||||
|
||||
supportsAssist =
|
||||
(onConversationVersion && !onPipelineVersion && config?.components?.contains("conversation") == true) ||
|
||||
(onPipelineVersion && config?.components?.contains("assist_pipeline") == true)
|
||||
useAssistPipeline = onPipelineVersion
|
||||
}
|
||||
|
||||
isHapticEnabled.value = wearPrefsRepository.getWearHapticFeedback()
|
||||
checkSupportProgress = false
|
||||
}
|
||||
|
|
|
@ -56,8 +56,13 @@ fun ConversationResultView(
|
|||
SpeechBubble(
|
||||
text = conversationViewModel.speechResult.ifEmpty {
|
||||
when {
|
||||
(conversationViewModel.supportsConversation) -> stringResource(R.string.no_results)
|
||||
(!conversationViewModel.supportsConversation && !conversationViewModel.checkSupportProgress) -> stringResource(R.string.no_conversation_support)
|
||||
conversationViewModel.supportsAssist -> stringResource(R.string.no_results)
|
||||
(!conversationViewModel.supportsAssist && !conversationViewModel.checkSupportProgress) ->
|
||||
if (conversationViewModel.useAssistPipeline) {
|
||||
stringResource(R.string.no_assist_support, "2023.5", stringResource(R.string.no_assist_support_assist_pipeline))
|
||||
} else {
|
||||
stringResource(R.string.no_assist_support, "2023.1", stringResource(R.string.no_assist_support_conversation))
|
||||
}
|
||||
(!conversationViewModel.isRegistered) -> stringResource(R.string.not_registered)
|
||||
else -> "..."
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import io.homeassistant.companion.android.database.wear.getAll
|
|||
import io.homeassistant.companion.android.database.wear.getAllFlow
|
||||
import io.homeassistant.companion.android.sensors.SensorReceiver
|
||||
import io.homeassistant.companion.android.util.RegistriesDataHandler
|
||||
import io.homeassistant.companion.android.util.throttleLatest
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -217,7 +218,7 @@ class MainViewModel @Inject constructor(
|
|||
if (!homePresenter.isConnected() || isFavoritesOnly) {
|
||||
return
|
||||
}
|
||||
homePresenter.getAreaRegistryUpdates()?.collect {
|
||||
homePresenter.getAreaRegistryUpdates()?.throttleLatest(1000)?.collect {
|
||||
areaRegistry = homePresenter.getAreaRegistry()
|
||||
areas.clear()
|
||||
areaRegistry?.let {
|
||||
|
@ -231,7 +232,7 @@ class MainViewModel @Inject constructor(
|
|||
if (!homePresenter.isConnected() || isFavoritesOnly) {
|
||||
return
|
||||
}
|
||||
homePresenter.getDeviceRegistryUpdates()?.collect {
|
||||
homePresenter.getDeviceRegistryUpdates()?.throttleLatest(1000)?.collect {
|
||||
deviceRegistry = homePresenter.getDeviceRegistry()
|
||||
updateEntityDomains()
|
||||
}
|
||||
|
@ -241,7 +242,7 @@ class MainViewModel @Inject constructor(
|
|||
if (!homePresenter.isConnected()) {
|
||||
return
|
||||
}
|
||||
homePresenter.getEntityRegistryUpdates()?.collect {
|
||||
homePresenter.getEntityRegistryUpdates()?.throttleLatest(1000)?.collect {
|
||||
entityRegistry = homePresenter.getEntityRegistry()
|
||||
_supportedEntities.value = getSupportedEntities()
|
||||
updateEntityDomains()
|
||||
|
|
Loading…
Reference in a new issue