mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor(graphs): Missing iaq (#1752)
This commit is contained in:
parent
64c13ac57d
commit
309ce27268
4 changed files with 230 additions and 171 deletions
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.geeksville.mesh.model
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.geeksville.mesh.TelemetryProtos.Telemetry
|
||||
import com.geeksville.mesh.ui.theme.InfantryBlue
|
||||
import com.geeksville.mesh.ui.theme.Orange
|
||||
|
||||
enum class Environment(val color: Color) {
|
||||
TEMPERATURE(Color.Red) {
|
||||
override fun getValue(telemetry: Telemetry): Float {
|
||||
return telemetry.environmentMetrics.temperature
|
||||
}
|
||||
},
|
||||
HUMIDITY(InfantryBlue) {
|
||||
override fun getValue(telemetry: Telemetry): Float {
|
||||
return telemetry.environmentMetrics.relativeHumidity
|
||||
}
|
||||
},
|
||||
IAQ(Color.Green) {
|
||||
override fun getValue(telemetry: Telemetry): Float {
|
||||
return telemetry.environmentMetrics.iaq.toFloat()
|
||||
}
|
||||
},
|
||||
BAROMETRIC_PRESSURE(Orange) {
|
||||
override fun getValue(telemetry: Telemetry): Float {
|
||||
return telemetry.environmentMetrics.barometricPressure
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun getValue(telemetry: Telemetry): Float
|
||||
}
|
||||
|
||||
/**
|
||||
* @param metrics the filtered [List]
|
||||
* @param shouldPlot a [List] the size of [Environment] used to determine if a metric
|
||||
* should be plotted
|
||||
* @param leftMinMax [Pair] with the min and max of the barometric pressure
|
||||
* @param rightMinMax [Pair] with the combined min and max of: the temperature, humidity, and IAQ
|
||||
* @param times [Pair] with the oldest and newest times in that order
|
||||
*/
|
||||
data class EnvironmentGraphingData(
|
||||
val metrics: List<Telemetry>,
|
||||
val shouldPlot: List<Boolean>,
|
||||
val leftMinMax: Pair<Float, Float> = Pair(0f, 0f),
|
||||
val rightMinMax: Pair<Float, Float> = Pair(0f, 0f),
|
||||
val times: Pair<Int, Int> = Pair(0, 0)
|
||||
)
|
||||
|
||||
data class EnvironmentMetricsState(
|
||||
val environmentMetrics: List<Telemetry> = emptyList(),
|
||||
) {
|
||||
fun hasEnvironmentMetrics() = environmentMetrics.isNotEmpty()
|
||||
|
||||
/**
|
||||
* Filters [environmentMetrics] based on a [TimeFrame].
|
||||
*
|
||||
* @param timeFrame used to filter
|
||||
* @return [EnvironmentGraphingData]
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
fun environmentMetricsFiltered(timeFrame: TimeFrame): EnvironmentGraphingData {
|
||||
val oldestTime = timeFrame.calculateOldestTime()
|
||||
val telemetries = environmentMetrics.filter { it.time >= oldestTime }
|
||||
val shouldPlot = BooleanArray(Environment.entries.size) { false }
|
||||
if (telemetries.isEmpty()) {
|
||||
return EnvironmentGraphingData(metrics = telemetries, shouldPlot = shouldPlot.toList())
|
||||
}
|
||||
|
||||
/* Grab the combined min and max for temp, humidity, and iaq. */
|
||||
val minValues = mutableListOf<Float>()
|
||||
val maxValues = mutableListOf<Float>()
|
||||
val (minTemp, maxTemp) = Pair(
|
||||
telemetries.minBy { it.environmentMetrics.temperature },
|
||||
telemetries.maxBy { it.environmentMetrics.temperature }
|
||||
)
|
||||
if (minTemp.environmentMetrics.temperature != 0f || maxTemp.environmentMetrics.temperature != 0f) {
|
||||
minValues.add(minTemp.environmentMetrics.temperature)
|
||||
maxValues.add(maxTemp.environmentMetrics.temperature)
|
||||
shouldPlot[Environment.TEMPERATURE.ordinal] = true
|
||||
}
|
||||
|
||||
val (minHumidity, maxHumidity) = Pair(
|
||||
telemetries.minBy { it.environmentMetrics.relativeHumidity },
|
||||
telemetries.maxBy { it.environmentMetrics.relativeHumidity }
|
||||
)
|
||||
if (minHumidity.environmentMetrics.relativeHumidity != 0f ||
|
||||
maxHumidity.environmentMetrics.relativeHumidity != 0f) {
|
||||
minValues.add(minHumidity.environmentMetrics.relativeHumidity)
|
||||
maxValues.add(maxHumidity.environmentMetrics.relativeHumidity)
|
||||
shouldPlot[Environment.HUMIDITY.ordinal] = true
|
||||
}
|
||||
|
||||
val (minIAQ, maxIAQ) = Pair(
|
||||
telemetries.minBy { it.environmentMetrics.iaq },
|
||||
telemetries.maxBy { it.environmentMetrics.iaq }
|
||||
)
|
||||
if (minIAQ.environmentMetrics.iaq != 0 || maxIAQ.environmentMetrics.iaq != 0) {
|
||||
minValues.add(minIAQ.environmentMetrics.iaq.toFloat())
|
||||
maxValues.add(maxIAQ.environmentMetrics.iaq.toFloat())
|
||||
shouldPlot[Environment.IAQ.ordinal] = true
|
||||
}
|
||||
|
||||
val min = minValues.minOf { it }
|
||||
val max = maxValues.maxOf { it }
|
||||
|
||||
val (minPressure, maxPressure) = Pair(
|
||||
telemetries.minBy { it.environmentMetrics.barometricPressure },
|
||||
telemetries.maxBy { it.environmentMetrics.barometricPressure }
|
||||
)
|
||||
if (minPressure.environmentMetrics.barometricPressure != 0.0F &&
|
||||
maxPressure.environmentMetrics.barometricPressure != 0.0F) {
|
||||
shouldPlot[Environment.BAROMETRIC_PRESSURE.ordinal] = true
|
||||
}
|
||||
val (oldest, newest) = Pair(
|
||||
telemetries.minBy { it.time },
|
||||
telemetries.maxBy { it.time }
|
||||
)
|
||||
|
||||
return EnvironmentGraphingData(
|
||||
metrics = telemetries,
|
||||
shouldPlot = shouldPlot.toList(),
|
||||
leftMinMax = Pair(
|
||||
minPressure.environmentMetrics.barometricPressure,
|
||||
maxPressure.environmentMetrics.barometricPressure
|
||||
),
|
||||
rightMinMax = Pair(min, max),
|
||||
times = Pair(oldest.time, newest.time)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -71,7 +71,6 @@ data class MetricsState(
|
|||
val displayUnits: DisplayUnits = DisplayUnits.METRIC,
|
||||
val node: Node? = null,
|
||||
val deviceMetrics: List<Telemetry> = emptyList(),
|
||||
val environmentMetrics: List<Telemetry> = emptyList(),
|
||||
val signalMetrics: List<MeshPacket> = emptyList(),
|
||||
val powerMetrics: List<Telemetry> = emptyList(),
|
||||
val tracerouteRequests: List<MeshLog> = emptyList(),
|
||||
|
|
@ -80,7 +79,6 @@ data class MetricsState(
|
|||
val deviceHardware: DeviceHardware? = null,
|
||||
) {
|
||||
fun hasDeviceMetrics() = deviceMetrics.isNotEmpty()
|
||||
fun hasEnvironmentMetrics() = environmentMetrics.isNotEmpty()
|
||||
fun hasSignalMetrics() = signalMetrics.isNotEmpty()
|
||||
fun hasPowerMetrics() = powerMetrics.isNotEmpty()
|
||||
fun hasTracerouteLogs() = tracerouteRequests.isNotEmpty()
|
||||
|
|
@ -91,11 +89,6 @@ data class MetricsState(
|
|||
return deviceMetrics.filter { it.time >= oldestTime }
|
||||
}
|
||||
|
||||
fun environmentMetricsFiltered(timeFrame: TimeFrame): List<Telemetry> {
|
||||
val oldestTime = timeFrame.calculateOldestTime()
|
||||
return environmentMetrics.filter { it.time >= oldestTime }
|
||||
}
|
||||
|
||||
fun signalMetricsFiltered(timeFrame: TimeFrame): List<MeshPacket> {
|
||||
val oldestTime = timeFrame.calculateOldestTime()
|
||||
return signalMetrics.filter { it.rxTime >= oldestTime }
|
||||
|
|
@ -217,6 +210,9 @@ class MetricsViewModel @Inject constructor(
|
|||
private val _state = MutableStateFlow(MetricsState.Empty)
|
||||
val state: StateFlow<MetricsState> = _state
|
||||
|
||||
private val _envState = MutableStateFlow(EnvironmentMetricsState())
|
||||
val environmentState: StateFlow<EnvironmentMetricsState> = _envState
|
||||
|
||||
private val _timeFrame = MutableStateFlow(TimeFrame.TWENTY_FOUR_HOURS)
|
||||
val timeFrame: StateFlow<TimeFrame> = _timeFrame
|
||||
|
||||
|
|
@ -253,12 +249,16 @@ class MetricsViewModel @Inject constructor(
|
|||
_state.update { state ->
|
||||
state.copy(
|
||||
deviceMetrics = telemetry.filter { it.hasDeviceMetrics() },
|
||||
powerMetrics = telemetry.filter { it.hasPowerMetrics() }
|
||||
)
|
||||
}
|
||||
_envState.update { state ->
|
||||
state.copy(
|
||||
environmentMetrics = telemetry.filter {
|
||||
it.hasEnvironmentMetrics() &&
|
||||
it.environmentMetrics.relativeHumidity >= 0f &&
|
||||
!it.environmentMetrics.temperature.isNaN()
|
||||
},
|
||||
powerMetrics = telemetry.filter { it.hasPowerMetrics() }
|
||||
)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue