Add soil temperature and soil moisture environmental metrics to app (#2419)

Co-authored-by: DaneEvans <dane@goneepic.com>
This commit is contained in:
Justin E. Mann 2025-07-12 07:52:06 -06:00 committed by GitHub
parent 8a0ad26d4e
commit fbd62cbf10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 158 additions and 14 deletions

View file

@ -21,6 +21,8 @@ import androidx.compose.ui.graphics.Color
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.ui.common.theme.InfantryBlue
import com.geeksville.mesh.ui.common.theme.Orange
import com.geeksville.mesh.ui.common.theme.Pink
import com.geeksville.mesh.ui.common.theme.Purple
import com.geeksville.mesh.util.UnitConversions
enum class Environment(val color: Color) {
@ -34,6 +36,16 @@ enum class Environment(val color: Color) {
return telemetry.environmentMetrics.relativeHumidity
}
},
SOIL_TEMPERATURE(Pink) {
override fun getValue(telemetry: Telemetry): Float {
return telemetry.environmentMetrics.soilTemperature
}
},
SOIL_MOISTURE(Purple) {
override fun getValue(telemetry: Telemetry): Float {
return telemetry.environmentMetrics.soilMoisture.toFloat()
}
},
IAQ(Color.Green) {
override fun getValue(telemetry: Telemetry): Float {
return telemetry.environmentMetrics.iaq.toFloat()
@ -75,7 +87,7 @@ data class EnvironmentMetricsState(
* @param timeFrame used to filter
* @return [EnvironmentGraphingData]
*/
@Suppress("LongMethod")
@Suppress("LongMethod", "CyclomaticComplexMethod", "MagicNumber")
fun environmentMetricsFiltered(timeFrame: TimeFrame, useFahrenheit: Boolean = false): EnvironmentGraphingData {
val oldestTime = timeFrame.calculateOldestTime()
val telemetries = environmentMetrics.filter { it.time >= oldestTime }
@ -84,7 +96,7 @@ data class EnvironmentMetricsState(
return EnvironmentGraphingData(metrics = telemetries, shouldPlot = shouldPlot.toList())
}
/* Grab the combined min and max for temp, humidity, and iaq. */
/* Grab the combined min and max for temp, humidity, soil_Temperature, soilMoisture and iaq. */
val minValues = mutableListOf<Float>()
val maxValues = mutableListOf<Float>()
val (minTemp, maxTemp) = Pair(
@ -114,6 +126,31 @@ data class EnvironmentMetricsState(
shouldPlot[Environment.HUMIDITY.ordinal] = true
}
var minSoilTemperatureValue = minTemp.environmentMetrics.soilTemperature
var maxSoilTemperatureValue = maxTemp.environmentMetrics.soilTemperature
if (useFahrenheit) {
minSoilTemperatureValue = UnitConversions.celsiusToFahrenheit(minSoilTemperatureValue)
maxSoilTemperatureValue = UnitConversions.celsiusToFahrenheit(maxSoilTemperatureValue)
}
if (minTemp.environmentMetrics.soilTemperature != 0f ||
maxTemp.environmentMetrics.soilTemperature != 0f) {
minValues.add(minSoilTemperatureValue)
maxValues.add(maxSoilTemperatureValue)
shouldPlot[Environment.SOIL_TEMPERATURE.ordinal] = true
}
val (minSoilMoisture, maxSoilMoisture) = Pair(
telemetries.minBy { it.environmentMetrics.soilMoisture },
telemetries.maxBy { it.environmentMetrics.soilMoisture }
)
val soilMoistureRange = 0..100
if (minSoilMoisture.environmentMetrics.soilMoisture in soilMoistureRange ||
maxSoilMoisture.environmentMetrics.soilMoisture in soilMoistureRange) {
minValues.add(minSoilMoisture.environmentMetrics.soilMoisture.toFloat())
maxValues.add(maxSoilMoisture.environmentMetrics.soilMoisture.toFloat())
shouldPlot[Environment.SOIL_MOISTURE.ordinal] = true
}
val (minIAQ, maxIAQ) = Pair(
telemetries.minBy { it.environmentMetrics.iaq },
telemetries.maxBy { it.environmentMetrics.iaq }

View file

@ -27,6 +27,7 @@ import com.geeksville.mesh.TelemetryProtos.EnvironmentMetrics
import com.geeksville.mesh.TelemetryProtos.PowerMetrics
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.util.GPSFormat
import com.geeksville.mesh.util.UnitConversions.celsiusToFahrenheit
import com.geeksville.mesh.util.latLongToMeter
import com.geeksville.mesh.util.toDistanceString
import com.google.protobuf.ByteString
@ -113,8 +114,7 @@ data class Node(
private fun EnvironmentMetrics.getDisplayString(isFahrenheit: Boolean): String {
val temp = if (temperature != 0f) {
if (isFahrenheit) {
val fahrenheit = temperature * 1.8F + 32
"%.1f°F".format(fahrenheit)
"%.1f°F".format(celsiusToFahrenheit(temperature))
} else {
"%.1f°C".format(temperature)
}
@ -122,6 +122,20 @@ data class Node(
null
}
val humidity = if (relativeHumidity != 0f) "%.0f%%".format(relativeHumidity) else null
val soilTemperatureStr = if (soilTemperature != 0f) {
if (isFahrenheit) {
"%.1f°F".format(celsiusToFahrenheit(temperature))
} else {
"%.1f°C".format(soilTemperature)
}
} else {
null
}
val soilMoistureRange = 0..100
val soilMoisture =
if (soilMoisture in soilMoistureRange && soilTemperature != 0f) {
"%d%%".format(soilMoisture)
} else { null }
val voltage = if (this.voltage != 0f) "%.2fV".format(this.voltage) else null
val current = if (current != 0f) "%.1fmA".format(current) else null
val iaq = if (iaq != 0) "IAQ: $iaq" else null
@ -129,6 +143,8 @@ data class Node(
return listOfNotNull(
temp,
humidity,
soilTemperatureStr,
soilMoisture,
voltage,
current,
iaq,