package com.geeksville.mesh.model import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.geeksville.mesh.R import com.geeksville.mesh.TelemetryProtos.Telemetry import com.geeksville.mesh.database.MeshLogRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.enums.EnumEntries enum class MetricsPage( @StringRes val titleResId: Int, @DrawableRes val drawableResId: Int, ) { DEVICE(R.string.device, R.drawable.baseline_charging_station_24), ENVIRONMENT(R.string.environment, R.drawable.baseline_thermostat_24), } data class MetricsState( val pages: EnumEntries = MetricsPage.entries, val isLoading: Boolean = false, val deviceMetrics: List = emptyList(), val environmentMetrics: List = emptyList(), ) { companion object { val Empty = MetricsState() } } @HiltViewModel class MetricsViewModel @Inject constructor( val nodeDB: NodeDB, private val meshLogRepository: MeshLogRepository ) : ViewModel() { private val isLoading = MutableStateFlow(false) private val _deviceMetrics = MutableStateFlow>(emptyList()) private val _environmentMetrics = MutableStateFlow>(emptyList()) val state = combine( isLoading, _deviceMetrics, _environmentMetrics, ) { isLoading, device, environment -> MetricsState( isLoading = isLoading, deviceMetrics = device, environmentMetrics = environment, ) }.stateIn( scope = viewModelScope, started = WhileSubscribed(5_000), initialValue = MetricsState.Empty, ) /** * Gets the short name of the node identified by `nodeNum`. */ fun getNodeName(nodeNum: Int): String? = nodeDB.nodeDBbyNum.value[nodeNum]?.user?.shortName /** * Used to set the Node for which the user will see charts for. */ fun setSelectedNode(nodeNum: Int) { viewModelScope.launch { isLoading.value = true meshLogRepository.getTelemetryFrom(nodeNum).collect { val deviceList = mutableListOf() val environmentList = mutableListOf() for (telemetry in it) { if (telemetry.hasDeviceMetrics()) deviceList.add(telemetry) /* Avoiding negative outliers */ if (telemetry.hasEnvironmentMetrics() && telemetry.environmentMetrics.relativeHumidity >= 0f) environmentList.add(telemetry) } _deviceMetrics.value = deviceList _environmentMetrics.value = environmentList isLoading.value = false } } } }